日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

深入了解EntityFramework——Fluent API

發布時間:2025/3/11 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入了解EntityFramework——Fluent API 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Fluent API??

除了慣例原則與屬性數據注解外,FluentAPI是另一種支持實體類配置設置的方式。與屬性數據注解相比,它提供了更廣泛的功能與設置彈性。實體類若同時設置了數據注解,則采用的優先權是“Fluent API” > "數據注解" > "慣例"。一旦設置了Fluent API 無論數據注解還是慣例規則均會被覆蓋。

DbContext類定義的OnModelCreating 方法是最常調用FLuent API的地方,如下圖所示:

public class SchoolContext: DbContext {public KTStoreContext():base("name=KTStore"){}public DbSet<Product> Products { get; set; }protected override void OnModelCreating(DbModelBuilder modelBuilder){//Write Fluent API configurations here} }

?

常用的Fluent API方法
配置Fluent API方法作用
架構相關配置HasDefaultSchema()數據庫的默認架構
ComplexType()把一個類配置為復雜類型
實體相關配置HasIndex()實體的的索引
HasKey()實體的主鍵(可其實現復合主鍵,[Key]在EF?core中不能實現復合主鍵)
HasMany()1對多的或者?多對多關系?
HasOptional()一個可選的關系,這樣配置會在數據庫中生成一個可空的外鍵
HasRequired()一個必有的關系,這樣配置會在數據庫中生成一個不能為空的外鍵
Ignore()實體或者實體的屬性不映射到數據庫
Map()設置一些優先的配置
MapToStoredProcedures()實體的CUD操作使用存儲過程
ToTable()為實體設置表名
屬性相關配置HasColumnAnnotation()給屬性設置注釋
IsRequired()在調用SaveChanges()方法時,屬性不能為空
IsOptional()可選的,在數據庫生成可空的列
HasParameterName()配置用于該屬性的存儲過程的參數名
HasDatabaseGeneratedOption()配置數據庫中對應列的值怎樣生成的,如計算,自增等
HasColumnOrder()配置數據庫中對應列的排列順序
HasColumnType()配置數據庫中對應列的數據類型
HasColumnName()配置數據庫中對應列的列名
IsConcurrencyToken()配置數據庫中對應列用于樂觀并發檢測

舉一個簡單例子,?新建一個FluentApiDemo的控制臺應用程序,添加Product實體類和上下文類KTStoreModel,如下圖所示:

namespace FluentApiDemo {public class Product{public int XPId { get; set; }public string Name { get; set; }public int Price { get; set; }public int SPrice { get; set; }public string Category { get; set; }} } public class KTStoreModel : DbContext{public KTStoreModel(): base("name=KTStoreModel"){}protected override void OnModelCreating(DbModelBuilder modelBuilder){modelBuilder.Entity<Product>().ToTable("tbProduct");modelBuilder.Entity<Product>().HasKey(p => p.XPId);modelBuilder.Entity<Product>().Property(p => p.Name).HasColumnName("ProductName");modelBuilder.Entity<Product>().Property(p => p.Name).HasMaxLength(50);modelBuilder.Entity<Product>().Property(p => p.Name).IsRequired();modelBuilder.Entity<Product>().Property(p => p.Price).HasColumnName("ProductPrice");modelBuilder.Entity<Product>().Ignore(p => p.SPrice);base.OnModelCreating(modelBuilder);}public virtual DbSet<Product> Product { get; set; }}

Main函數中的代碼如下圖所示:

class Program{static void Main(string[] args){using (KTStoreModel db = new KTStoreModel()){Console.Write("count:{0}",db.Product.Count());Console.ReadKey();}}}

運行后在數據庫生成的表結果如下圖所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

?


?CodeFirst配置一對一,一對多,多對多關系

產品類Product和書本類Book是典型的一對一關系,產品中可能有書本這個屬性,也可能沒書本這個屬性。但是書本必屬于產品的一部分。

public class Product{public int Id { get; set; }public string Name { get; set;}public int CategoryId { get; set; }public int Price { get; set; }//導航屬性public virtual Book Book { get; set; } } public class Book{public int Id { get; set; }public int Pages { get; set; }public string ISBN { get; set; }public string Author { get; set; }public string Publisher { get; set; }//導航屬性public virtual Product Product { get; set; }}

?使用Fluent API配置如下:

public class kTStoreModel : DbContext{public kTStoreModel(): base("name=kTStoreModel"){}protected override void OnModelCreating(DbModelBuilder modelBuilder){modelBuilder.Entity<Product>().HasOptional(e => e.Book)//給Product設置可空的Book屬性.WithRequired(e => e.Product);//給Book設置不能為空的Product屬性,沒有Book屬性時不能保存}public virtual DbSet<Product> Product { get; set; }public virtual DbSet<Book> Book { get; set; }}

生成的數據表結構如下圖所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ???

?

書本類Book和作者類Author是典型的多對多關系,一本書可能有多個作者,一個作者可能寫了多本書。?

public class Book{public int Id { get; set; }public int Pages { get; set; }public string ISBN { get; set; }public string Publisher { get; set; }//導航屬性public virtual List<Author> Author { get; set; }} public class Author{public int Id { get; set; }public string Name { get; set; }//導航屬性public virtual List<Book> Book { get; set; }}

??使用Fluent API配置如下:

public class kTStoreModel : DbContext{public kTStoreModel(): base("name=kTStoreModel"){}protected override void OnModelCreating(DbModelBuilder modelBuilder){modelBuilder.Entity<Author>().HasMany(e => e.Book)//配置一個作者有多本書.WithMany(e => e.Author)//配置一本書有多個作者.Map(m => m.ToTable("BookAuthor")//生成BookAuthor中間表.MapLeftKey("AuthorId")//因為是通過Entity<Author>開始的,所以左表是Author.MapRightKey("BookId"));//又表是BookId}public virtual DbSet<Book> Book { get; set; }public virtual DbSet<Author> Author { get; set; }}

生成的數據庫表結構如下圖所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??


多對多關聯——附加數據字段?

還有一種多對多關聯的情況是,存儲兩個數據表關聯信息的數據庫表?本身具有其他有效的數據字段。這種情況下,實體數據模型必須為此數據表建立起專用的數據類型。

?產品Product類和訂單Order類是一個多對多的關系,OrderDetail存儲兩個數據表的關聯信息,并且OrderDetail表中存在其他數據字段。

public class Product{public int Id { get; set; }public string Name { get; set;}public int Price { get; set; }//導航屬性public virtual List<OrderDetail> OrderDetail { get; set; } } public class Order{public int Id { get; set; }public DateTime OrderDate { get; set; }//導航屬性public virtual List<OrderDetail> OrderDetail { get; set; }} public class OrderDetail{[Key][Column(Order = 0)][DatabaseGenerated(DatabaseGeneratedOption.None)]public int OrderId { get; set; }[Key][Column(Order = 1)][DatabaseGenerated(DatabaseGeneratedOption.None)]public int ProductId { get; set; }public int Quantity { get; set; }public int Price { get; set; }//導航屬性public virtual Product Product { get; set; }public virtual Order Order { get; set; }}

?運行后建立的數據庫表結構如下圖所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?


訂單系統中,訂單主表和明細表是典型的一對多關系。?

public class Order{public int Id { get; set; }public DateTime OrderDate { get; set; }//導航屬性public virtual List<OrderDetail> OrderDetail { get; set; }} public class OrderDetail{public int Id { get; set; }public string ProductName { get; set; }public int Quantity { get; set; }public int Price { get; set; }public int XOrderId { get; set; }//導航屬性public virtual Order Order { get; set; }}

使用Fluent API配置如下:

public class kTStoreModel : DbContext{public kTStoreModel(): base("name=kTStoreModel"){}protected override void OnModelCreating(DbModelBuilder modelBuilder){modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();//取消數據庫表復數形式modelBuilder.Entity<OrderDetail>().HasRequired(od => od.Order)//OrderDetail有必須要的導航屬性Order.WithMany(o => o.OrderDetail)//OrderDetail有集體導航屬性OrderDetail.HasForeignKey(x => x.XOrderId);//設置外鍵 }public virtual DbSet<Order> Order { get; set; }public virtual DbSet<OrderDetail> OrderDetail { get; set; }}

?也可以使用Fluent API 反向關聯,代碼如下:

modelBuilder.Entity<Order>().HasMany(o => o.OrderDetail).WithRequired(od => od.Order).HasForeignKey(od => od.XOrderId);

運行后建立的數據庫表結構如下圖所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??


?級聯刪除

級聯刪除是指父級記錄刪除時會自動刪除子級記錄。比如訂單主表刪除后自動刪除訂單從表。

在EF中,默認是打開級聯刪除的。

一對多:如訂單主表刪除時,訂單從表從中外鍵OrderId變成null。

一對一:如刪除Product時,對應的Book也會刪除。

多對多:如刪除一種book信息時,在中間表中對應的作者信息也會刪除。

代碼如下圖所示:

modelBuilder.Entity<OrderDetail>().HasRequired(od => od.Order).WithMany(o => o.OrderDetail).HasForeignKey(x => x.XOrderId).WillCascadeOnDelete();//開啟級聯刪除modelBuilder.Entity<Order>().HasMany(o => o.OrderDetail).WithRequired(od => od.Order).HasForeignKey(od => od.XOrderId).WillCascadeOnDelete(false);//關閉級聯刪除

配置單個實體

我們已經知道了在OnModelCreating()方法中可以通過FluentApi對所有的實體類進行配置,然而當實體類很多時,我們把所有的配置都放在OnModelCreating()方法中很難維護。EF6允許我們給每一個實體添加一個單獨的配置類,通過這個配置類來對相應的實體進行配置。

以配置Student實體類為例,我們在OnModelCreating()方法中配置Student實體,代碼如下:

public DbSet<Student> Students { get; set; }protected override void OnModelCreating(DbModelBuilder modelBuilder){modelBuilder.Entity<Student>().ToTable("StudentInfo");modelBuilder.Entity<Student>().HasKey<int>(s => s.StudentKey);modelBuilder.Entity<Student>().Property(p => p.DateOfBirth).HasColumnName("Birthday").HasColumnOrder(3).HasColumnType("datetime2");modelBuilder.Entity<Student>().Property(p => p.StudentName).HasMaxLength(50);modelBuilder.Entity<Student>().Property(p => p.StudentName).IsConcurrencyToken();modelBuilder.Entity<Student>().HasMany<Course>(s => s.Courses).WithMany(c => c.Students).Map(cs =>{cs.MapLeftKey("StudentId");cs.MapRightKey("CourseId");cs.ToTable("StudentCourse");});} }

我們可以將每個實體類的配置放在一個對應的的配置類,(如Studnet的實體配置在StudentEntityConfiguratinos配置類中),如果程序中有很多實體類,采用單獨配置的方式可以很好的提高配置的可維護性和可讀性。

?StudentEntityConfiguratinos類需要繼承EntityTypeConfiguration<TEntity>:

public class StudentEntityConfiguration: EntityTypeConfiguration<Student> {public StudentEntityConfiguration(){this.ToTable("StudentInfo");this.HasKey<int>(s => s.StudentKey);this.Property(p => p.DateOfBirth).HasColumnName("DoB").HasColumnOrder(3).HasColumnType("datetime2");this.Property(p => p.StudentName).HasMaxLength(50);this.Property(p => p.StudentName).IsConcurrencyToken();this.HasMany<Course>(s => s.Courses).WithMany(c => c.Students).Map(cs =>{cs.MapLeftKey("StudentId");cs.MapRightKey("CourseId");cs.ToTable("StudentCourse");});} }

在OnModelCreating()方法中使用上邊的配置類

public class SchoolDBContext: DbContext {public SchoolDBContext(): base() {}public DbSet<Student> Students { get; set; }protected override void OnModelCreating(DbModelBuilder modelBuilder){// 添加Student實體的配置modelBuilder.Configurations.Add(new StudentEntityConfiguration());} }

?

?

?

?

?

?

?

?

?

?

總結

以上是生活随笔為你收集整理的深入了解EntityFramework——Fluent API的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。