ASP.NET?Core使用EF創(chuàng)建關(guān)系模型
1.關(guān)系
關(guān)系定義兩個實體之間的關(guān)系。在關(guān)系型數(shù)據(jù)庫中,這由外鍵約束表示。
2.術(shù)語定義
有許多術(shù)語用于描述關(guān)系:
- 相關(guān)實體:這是包含外鍵屬性的實體。有時稱為關(guān)系的"子級"。
- 主體實體:這是包含主/備用鍵屬性的實體。有時稱為關(guān)系的 "父項"。
- 外鍵:依賴實體中的屬性,用于存儲與實體相關(guān)的主體鍵屬性的值。
- 主體密鑰:唯一標識主體實體的屬性。這可能是主鍵或備用密鑰。
- 導(dǎo)航屬性:在主體和/或從屬實體上定義的屬性,該屬性包含對相關(guān)實體的引用。
- 集合導(dǎo)航屬性:一個導(dǎo)航屬性,其中包含對多個相關(guān)實體的引用。
- 引用導(dǎo)航屬性:保存對單個相關(guān)實體的引用的導(dǎo)航屬性。
- 反向?qū)Ш綄傩裕河懻撎囟▽?dǎo)航屬性時,此術(shù)語是指關(guān)系另一端的導(dǎo)航屬性。
下面的代碼列表顯示了與之間Blog的一對多關(guān)系Post
- Post是依賴實體
- Blog是主體實體
- Post.BlogId為外鍵
- Blog.BlogId是主體鍵(在這種情況下是主鍵,而不是備用鍵)
- Post.Blog是一個引用導(dǎo)航屬性
- Blog.Posts是集合導(dǎo)航屬性
- Post.Blog是的Blog.Posts反向?qū)Ш綄傩裕ǚ粗嗳唬?/li>
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.約定
按照約定,當發(fā)現(xiàn)類型上有導(dǎo)航屬性時,將創(chuàng)建關(guān)系。如果屬性指向的類型不能由當前的數(shù)據(jù)庫提供程序映射為標量類型,則該屬性視為一個導(dǎo)航屬性。
4.完全定義的關(guān)系
關(guān)系最常見的模式是在關(guān)系兩端定義導(dǎo)航屬性,在依賴實體類中定義外鍵屬性。
如果在兩個類型之間找到一對導(dǎo)航屬性,則這些屬性將配置為同一關(guān)系的反向?qū)Ш綄傩浴?br />如果依賴實體包含名為<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; }
//導(dǎo)航屬性
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; }
//反向?qū)Ш綄傩?
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; }
//陰影導(dǎo)航屬性
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
//陰影反向?qū)Ш綄傩?
public Blog Blog { get; set; }
}6.單個導(dǎo)航屬性
只包含一個導(dǎo)航屬性(無反向?qū)Ш?,沒有外鍵屬性)就足以具有約定定義的關(guān)系。 還可以有一個導(dǎo)航屬性和一個外鍵屬性。
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
//陰影導(dǎo)航屬性
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.數(shù)據(jù)注釋
可以使用兩個數(shù)據(jù)批注來配置關(guān)系[ForeignKey]和[InverseProperty]。System.ComponentModel.DataAnnotations.Schema命名空間中提供了這些項。
7.1ForeignKey
你可以使用數(shù)據(jù)批注來配置應(yīng)用程序作給定關(guān)系的外鍵屬性的屬性。通常,當不按約定發(fā)現(xiàn)外鍵屬性時,會執(zhí)行此操作。
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; }
//導(dǎo)航屬性
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; }
//設(shè)置反向?qū)Ш酵怄I
[ForeignKey("BlogForeignKey")]
public Blog Blog { get; set; }
}
#endregion
}7.2InverseProperty
您可以使用數(shù)據(jù)批注來配置依賴項和主體實體上的導(dǎo)航屬性如何配對。這通常在兩個實體類型之間存在多個導(dǎo)航屬性對時執(zhí)行。
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中配置關(guān)系,請首先標識構(gòu)成關(guān)系的導(dǎo)航屬性。HasOne或HasMany標識要開始配置的實體類型上的導(dǎo)航屬性。然后,將調(diào)用鏈接到WithOne或WithMany以標識反向?qū)Ш?。HasOne/WithOne用于引用導(dǎo)航屬性,HasMany / WithMany用于集合導(dǎo)航屬性。
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>()
//配置一對多關(guān)系
.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單個導(dǎo)航屬性
如果只有一個導(dǎo)航屬性,則用WithOne、WithMany的無參數(shù)重載。這表示在概念上,關(guān)系的另一端有一個引用或集合,但實體類中不包含導(dǎo)航屬性。
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>()
//配置多對一關(guān)系
.HasMany(b => b.Posts)
.WithOne();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
//導(dǎo)航屬性
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來配置應(yīng)用程序的外鍵屬性。
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>()
//配置一對多關(guān)系
.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; }
//導(dǎo)航屬性
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
}下面的代碼列表演示如何配置復(fù)合外鍵:
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>()
//配置復(fù)合主鍵
.HasKey(c => new { c.State, c.LicensePlate });
modelBuilder.Entity<RecordOfSale>()
//配置一對多關(guān)系
.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; }
//導(dǎo)航屬性
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對應(yīng)CarState
public string CarState { get; set; }
//LicensePlate 對應(yīng)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>()
//配置一對多關(guān)系
.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無導(dǎo)航屬性
不一定需要提供導(dǎo)航屬性。你可以直接在關(guān)系的一端提供外鍵。
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>()
//配置一對多關(guān)系
.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來配置關(guān)系的主體鍵屬性。 配置為主體密鑰的屬性將自動設(shè)置為備用密鑰。
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; }
}下面的代碼列表演示如何配置復(fù)合主體鍵:
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.必需和可選的關(guān)系
您可以使用熟知的API來配置是必需的還是可選的關(guān)系。最終,這會控制外鍵屬性是必需的還是可選的。當使用陰影狀態(tài)外鍵時,這非常有用。如果實體類中具有外鍵屬性,則關(guān)系的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.級聯(lián)刪除
您可以使用熟知的API顯式配置給定關(guān)系的級聯(lián)刪除行為。
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.其他關(guān)系模式
12.1一對一
一對多關(guān)系在兩側(cè)都有一個引用導(dǎo)航屬性。它們遵循與一對多關(guān)系相同的約定,但在外鍵屬性上引入了唯一索引,以確保只有一個依賴項與每個主體相關(guān)。
12.1.1數(shù)據(jù)注釋
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 配置關(guān)系時,請使用HasOne和WithOne方法。配置外鍵時,需要指定依賴實體類型,請注意以下列表HasForeignKey中提供的泛型參數(shù)。在一對多關(guān)系中,可以清楚地表明具有引用導(dǎo)航的實體是依賴項,并且具有集合的實體是主體。但這并不是一對一的關(guān)系,因此需要顯式定義它。
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多對多
目前尚不支持多對多關(guān)系,沒有實體類來表示聯(lián)接表。但是,您可以通過包含聯(lián)接表的實體類并映射兩個不同的一對多關(guān)系,來表示多對多關(guān)系。
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; }
}到此這篇關(guān)于ASP.NET Core使用EF創(chuàng)建關(guān)系模型的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- ASP.NET?Core使用EF查詢數(shù)據(jù)
- ASP.NET?Core使用EF為關(guān)系數(shù)據(jù)庫建模
- ASP.NET?Core使用EF創(chuàng)建模型(索引、備用鍵、繼承、支持字段)
- ASP.NET Core使用EF創(chuàng)建模型(必需和可選屬性、最大長度、并發(fā)標記、陰影屬性)
- ASP.NET?Core使用EF創(chuàng)建模型(包含屬性、排除屬性、主鍵和生成值)
- ASP.NET?Core基于現(xiàn)有數(shù)據(jù)庫創(chuàng)建EF模型
- EF?Core通過顯式編譯提高查詢性能
- ASP.NET Core使用EF保存數(shù)據(jù)、級聯(lián)刪除和事務(wù)使用
相關(guān)文章
在Asp.net網(wǎng)頁上寫讀Cookie的兩種不同語法介紹
asp.net開發(fā)時,為了存儲一些信息通常是Session與Cookie同時使用,本文將會補充一下Cookie相關(guān)的資料,感興趣的朋友可以了解一下在網(wǎng)頁上寫讀Cookie的實現(xiàn),希望本文對你有所幫助2013-01-01
在 asp.net core 的中間件中返回具體的頁面的實現(xiàn)方法
這篇文章主要介紹了在 asp.net core 的中間件中返回具體的頁面的實現(xiàn)方法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08
.NET的動態(tài)編譯與WS服務(wù)調(diào)用詳解
這篇文章介紹了.NET的動態(tài)編譯與WS服務(wù)調(diào)用詳解,有需要的朋友可以參考一下,希望對你有所幫助2013-07-07
使用母版頁時內(nèi)容頁如何使用css和javascript
由于網(wǎng)站的主要頻道頁和列表頁的頭部和底部都是一樣的,如果將每個頁面放在單獨的頁面中,當頭部和底部需要更改時維護量太大。于是想把頭部和底部做成母版頁,頻道頁和列表頁的具體內(nèi)容放到內(nèi)容頁中。這樣當頭和底需要改動時,只要修改一下母版頁就可以了。2009-08-08
asp.net 在線編輯word文檔 可保存到服務(wù)器
使用說明:該方法只在office xp 和 2003上 測試通過,2000及以下 版本沒試。2010-01-01
asp.net 自動將漢字轉(zhuǎn)換成拼音第一個字母
把漢字轉(zhuǎn)換成拼音第一個字母 的實現(xiàn)代碼2009-03-03

