1.關系
關系定義兩個物體之間的關系,在關系型資料庫中,這由外鍵約束表示,
2.術語定義
有許多術語用于描述關系:
●相關物體:這是包含外鍵屬性的物體,有時稱為關系的"子級",
●主體物體:這是包含主/備用鍵屬性的物體,有時稱為關系的 "父項",
●外鍵:依賴物體中的屬性,用于存盤與物體相關的主體鍵屬性的值,
●主體密鑰:唯一標識主體物體的屬性,這可能是主鍵或備用密鑰,
●導航屬性:在主體和/或從屬物體上定義的屬性,該屬性包含對相關物體的參考,
●集合導航屬性:一個導航屬性,其中包含對多個相關物體的參考,
●參考導航屬性:保存對單個相關物體的參考的導航屬性,
●反向導航屬性:討論特定導航屬性時,此術語是指關系另一端的導航屬性,
下面的代碼串列顯示了與之間Blog的一對多關系Post
●Post是依賴物體
●Blog是主體物體
●Post.BlogId為外鍵
●Blog.BlogId是主體鍵(在這種情況下是主鍵,而不是備用鍵)
●Post.Blog是一個參考導航屬性
●Blog.Posts是集合導航屬性
●Post.Blog是的Blog.Posts反向導航屬性(反之亦然)
public class Blog { public int BlogId { get; set; } public string Url { get; set; } public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public int BlogId { get; set; } public Blog Blog { get; set; } }
3.約定
按照約定,當發現型別上有導航屬性時,將創建關系,如果屬性指向的型別不能由當前的資料庫提供程式映射為標量型別,則該屬性視為一個導航屬性,
4.完全定義的關系
關系最常見的模式是在關系兩端定義導航屬性,在依賴物體類中定義外鍵屬性,
如果在兩個型別之間找到一對導航屬性,則這些屬性將配置為同一關系的反向導航屬性,
如果依賴物體包含名為<primary key property name>、<navigation property name><primary key property name>或<principal entity name><primary key property name>的屬性,則該屬性將被配置為外鍵,
public class Blog { public int BlogId { get; set; } public string Url { get; set; } //導航屬性 public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } //外鍵屬性 public int BlogId { get; set; } //反向導航屬性 public Blog Blog { get; set; } }
5.無外鍵屬性
盡管建議在依賴物體類中定義外鍵屬性,但這并不是必需的,如果未找到外鍵屬性,則會以該名稱<navigation property name><principal key property name>引入陰影外鍵屬性,
public class Blog { public int BlogId { get; set; } public string Url { get; set; } //陰影導航屬性 public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } //陰影反向導航屬性 public Blog Blog { get; set; } }
6.單個導航屬性
只包含一個導航屬性(無反向導航,沒有外鍵屬性)就足以具有約定定義的關系, 還可以有一個導航屬性和一個外鍵屬性,
public class Blog { public int BlogId { get; set; } public string Url { get; set; } //陰影導航屬性 public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } }
7.資料注釋
可以使用兩個資料批注來配置關系[ForeignKey]和[InverseProperty],System.ComponentModel.DataAnnotations.Schema命名空間中提供了這些項,
7.1ForeignKey
你可以使用資料批注來配置應用程式作給定關系的外鍵屬性的屬性,通常,當不按約定發現外鍵屬性時,會執行此操作,
namespace EFModeling.DataAnnotations.Relationships.ForeignKey { class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } } #region Entities public class Blog { public int BlogId { get; set; } public string Url { get; set; } //導航屬性 public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } //外鍵 public int BlogForeignKey { get; set; } //設定反向導航外鍵 [ForeignKey("BlogForeignKey")] public Blog Blog { get; set; } } #endregion }
7.2InverseProperty
您可以使用資料批注來配置依賴項和主體物體上的導航屬性如何配對,這通常在兩個物體型別之間存在多個導航屬性對時執行,
namespace EFModeling.DataAnnotations.Relationships.InverseProperty { class MyContext : DbContext { public DbSet<Post> Posts { get; set; } public DbSet<User> Users { get; set; } } #region Entities public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public int AuthorUserId { get; set; } public User Author { get; set; } public int ContributorUserId { get; set; } public User Contributor { get; set; } } public class User { public string UserId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } [InverseProperty("Author")] public List<Post> AuthoredPosts { get; set; } [InverseProperty("Contributor")] public List<Post> ContributedToPosts { get; set; } } #endregion }
8.Fluent API
若要在熟知的API中配置關系,請首先標識構成關系的導航屬性,HasOne或HasMany標識要開始配置的物體型別上的導航屬性,然后,將呼叫鏈接到WithOne或WithMany以標識反向導航,HasOne/WithOne用于參考導航屬性,HasMany / WithMany用于集合導航屬性,
namespace EFModeling.FluentAPI.Relationships.NoForeignKey { #region Model class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Post>() //配置一對多關系 .HasOne(p => p.Blog) .WithMany(b => b.Posts); } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public Blog Blog { get; set; } } #endregion }
8.1單個導航屬性
如果只有一個導航屬性,則用WithOne、WithMany的無引數多載,這表示在概念上,關系的另一端有一個參考或集合,但物體類中不包含導航屬性,
namespace EFModeling.FluentAPI.Relationships.OneNavigation { #region Model class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() //配置多對一關系 .HasMany(b => b.Posts) .WithOne(); } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } //導航屬性 public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } } #endregion }
8.2ForeignKey
你可以使用API來配置應用程式的外鍵屬性,
namespace EFModeling.Configuring.DataAnnotations.Samples.Relationships.ForeignKey { #region Model class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Post>() //配置一對多關系 .HasOne(p => p.Blog) .WithMany(b => b.Posts) //配置外鍵 .HasForeignKey(p => p.BlogForeignKey); } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } //導航屬性 public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } //外鍵 public int BlogForeignKey { get; set; } public Blog Blog { get; set; } } #endregion }
下面的代碼串列演示如何配置復合外鍵:
namespace EFModeling.Configuring.DataAnnotations.Samples.Relationships.CompositeForeignKey { #region Model class MyContext : DbContext { public DbSet<Car> Cars { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Car>() //配置復合主鍵 .HasKey(c => new { c.State, c.LicensePlate }); modelBuilder.Entity<RecordOfSale>() //配置一對多關系 .HasOne(s => s.Car) .WithMany(c => c.SaleHistory) //配置外鍵 .HasForeignKey(s => new { s.CarState, s.CarLicensePlate }); } } public class Car { public string State { get; set; } public string LicensePlate { get; set; } public string Make { get; set; } public string Model { get; set; } //導航屬性 public List<RecordOfSale> SaleHistory { get; set; } } public class RecordOfSale { public int RecordOfSaleId { get; set; } public DateTime DateSold { get; set; } public decimal Price { get; set; } //State對應CarState public string CarState { get; set; } //LicensePlate 對應CarLicensePlate public string CarLicensePlate { get; set; } public Car Car { get; set; } } #endregion }
您可以使用的HasForeignKey(...)字串多載將影子屬性配置為外鍵,建議先將影子屬性顯式添加到模型,然后再將其用作外鍵:
class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { // Add the shadow property to the model modelBuilder.Entity<Post>() //配置外鍵 .Property<int>("BlogForeignKey"); // Use the shadow property as a foreign key modelBuilder.Entity<Post>() //配置一對多關系 .HasOne(p => p.Blog) .WithMany(b => b.Posts) //配置外鍵 .HasForeignKey("BlogForeignKey"); } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public Blog Blog { get; set; } }
8.3無導航屬性
不一定需要提供導航屬性,你可以直接在關系的一端提供外鍵,
namespace EFModeling.FluentAPI.Relationships.NoNavigation { #region Model class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Post>() //配置一對多關系 .HasOne<Blog>() .WithMany() //配置外鍵 .HasForeignKey(p => p.BlogId); } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public int BlogId { get; set; } } #endregion }
9.主體密鑰
如果你希望外鍵參考主鍵之外的屬性,則可以使用熟知的API來配置關系的主體鍵屬性, 配置為主體密鑰的屬性將自動設定為備用密鑰,
class MyContext : DbContext { public DbSet<Car> Cars { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<RecordOfSale>() .HasOne(s => s.Car) .WithMany(c => c.SaleHistory) .HasForeignKey(s => s.CarLicensePlate) .HasPrincipalKey(c => c.LicensePlate); } } public class Car { public int CarId { get; set; } public string LicensePlate { get; set; } public string Make { get; set; } public string Model { get; set; } public List<RecordOfSale> SaleHistory { get; set; } } public class RecordOfSale { public int RecordOfSaleId { get; set; } public DateTime DateSold { get; set; } public decimal Price { get; set; } public string CarLicensePlate { get; set; } public Car Car { get; set; } }
下面的代碼串列演示如何配置復合主體鍵:
class MyContext : DbContext { public DbSet<Car> Cars { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<RecordOfSale>() .HasOne(s => s.Car) .WithMany(c => c.SaleHistory) .HasForeignKey(s => new { s.CarState, s.CarLicensePlate }) .HasPrincipalKey(c => new { c.State, c.LicensePlate }); } } public class Car { public int CarId { get; set; } public string State { get; set; } public string LicensePlate { get; set; } public string Make { get; set; } public string Model { get; set; } public List<RecordOfSale> SaleHistory { get; set; } } public class RecordOfSale { public int RecordOfSaleId { get; set; } public DateTime DateSold { get; set; } public decimal Price { get; set; } public string CarState { get; set; } public string CarLicensePlate { get; set; } public Car Car { get; set; } }
10.必需和可選的關系
您可以使用熟知的API來配置是必需的還是可選的關系,最終,這會控制外鍵屬性是必需的還是可選的,當使用陰影狀態外鍵時,這非常有用,如果物體類中具有外鍵屬性,則關系的requiredness取決于外鍵屬性是必需還是可選,
class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts) .IsRequired(); } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public Blog Blog { get; set; } }
11.級聯洗掉
您可以使用熟知的API顯式配置給定關系的級聯洗掉行為,
class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts) .OnDelete(DeleteBehavior.Cascade); } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public int? BlogId { get; set; } public Blog Blog { get; set; } }
12.其他關系模式
12.1一對一
一對多關系在兩側都有一個參考導航屬性,它們遵循與一對多關系相同的約定,但在外鍵屬性上引入了唯一索引,以確保只有一個依賴項與每個主體相關,
12.1.1資料注釋
public class Blog { public int BlogId { get; set; } public string Url { get; set; } public BlogImage BlogImage { get; set; } } public class BlogImage { public int BlogImageId { get; set; } public byte[] Image { get; set; } public string Caption { get; set; } public int BlogId { get; set; } public Blog Blog { get; set; } }
12.1.2Fluent API
使用API 配置關系時,請使用HasOne和WithOne方法,配置外鍵時,需要指定依賴物體型別,請注意以下串列HasForeignKey中提供的泛型引數,在一對多關系中,可以清楚地表明具有參考導航的物體是依賴項,并且具有集合的物體是主體,但這并不是一對一的關系,因此需要顯式定義它,
class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<BlogImage> BlogImages { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasOne(p => p.BlogImage) .WithOne(i => i.Blog) .HasForeignKey<BlogImage>(b => b.BlogForeignKey); } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } public BlogImage BlogImage { get; set; } } public class BlogImage { public int BlogImageId { get; set; } public byte[] Image { get; set; } public string Caption { get; set; } public int BlogForeignKey { get; set; } public Blog Blog { get; set; } }
12.2多對多
目前尚不支持多對多關系,沒有物體類來表示聯接表,但是,您可以通過包含聯接表的物體類并映射兩個不同的一對多關系,來表示多對多關系,
class MyContext : DbContext { public DbSet<Post> Posts { get; set; } public DbSet<Tag> Tags { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<PostTag>() .HasKey(pt => new { pt.PostId, pt.TagId }); modelBuilder.Entity<PostTag>() .HasOne(pt => pt.Post) .WithMany(p => p.PostTags) .HasForeignKey(pt => pt.PostId); modelBuilder.Entity<PostTag>() .HasOne(pt => pt.Tag) .WithMany(t => t.PostTags) .HasForeignKey(pt => pt.TagId); } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public List<PostTag> PostTags { get; set; } } public class Tag { public string TagId { get; set; } public List<PostTag> PostTags { get; set; } } public class PostTag { public int PostId { get; set; } public Post Post { get; set; } public string TagId { get; set; } public Tag Tag { get; set; } }
參考文獻:
關系
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/101946.html
標籤:.NET Core
上一篇:使用VS2019在WSL中開發除錯.NET Core
下一篇:檔案批量生成IO流讀寫
