一.索引 索引是許多數據存儲中的常見概念。雖然它們在數據存儲中的實現可能會有所不同,但它們可用於更有效地基於列(或列集)進行查找。按照約定,用作外鍵每個屬性 (或組的屬性) 會自動創建索引。無法使用數據註釋創建索引。 1.1 非唯一索引 Fluent API 在單個屬性上指定索引。預設情況下,索引是 ...
一.索引
索引是許多數據存儲中的常見概念。雖然它們在數據存儲中的實現可能會有所不同,但它們可用於更有效地基於列(或列集)進行查找。按照約定,用作外鍵每個屬性 (或組的屬性) 會自動創建索引。無法使用數據註釋創建索引。
1.1 非唯一索引
Fluent API 在單個屬性上指定索引。預設情況下,索引是非唯一的。如下代碼示例在Blogs表上創建Url列索引:
class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasIndex(b => b.Url); } }
1.2 唯一索引
下麵代碼指定索引是唯一的,這是在索引上加了(Unique)唯一約束。
modelBuilder.Entity<Blog>() .HasIndex(b => b.Url) .IsUnique();
1.3 複合索引
class MyContext : DbContext { public DbSet<People> People { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Person>() .HasIndex(p => new { p.FirstName, p.LastName }); } } public class People { public int PersonId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address{get;set;} }
下麵使用EF基於數據模型(People)創建數據表。在Migration中生成了索引的代碼, 以及查看資料庫People表的索引(官方文檔中暫沒有看到提供索引包含列設置)如下所示:
name: "IX_People_FirstName_LastName", table: "People", columns: new[] { "FirstName", "LastName" });
二.備用鍵
除主鍵之外,備用鍵用作每個實體實例的備用唯一標識符(跟主鍵一樣具有唯一約束)。備用鍵可以用作關係的目標。當使用關係資料庫時,這映射到備用鍵列上的唯一索引/約束的概念以及引用列的一個或多個外鍵約束。系統通常會在需要時為你引入備用鍵,你無需手動配置它們。不能使用數據註釋配置備用鍵。
2.1 約定
按照約定,系統將在識別屬性(不是主鍵)時為你引入備用鍵,充當關係的目標。如下麵代碼所示:
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) //Post中創建BlogUrl外建欄位 .HasForeignKey(p => p.BlogUrl) //Blog中設置唯一約束備份鍵 .HasPrincipalKey(b => b.Url); } } 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 string BlogUrl { get; set; } public Blog Blog { get; set; } }
上面主體實體Blog中Url屬性作為備用鍵,創建了AK_Blogs_Url唯一非聚集索引。在依賴實體Post中創建了BlogUrl外鍵欄位, 使用EF基於數據模型(Blog和Post實體)創建資料庫,如下圖所示。
2.2 Fluent API
可以使用Fluent API將單個屬性配置為備用鍵。
class MyContext : DbContext { public DbSet<Car> Cars { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Car>() //配置備用鍵(唯一非聚集索引) .HasAlternateKey(c => c.LicensePlate); // 創建複合備用鍵 // modelBuilder.Entity<Car>() // .HasAlternateKey(c => new { c.State, c.LicensePlate }); } } class Car { public int CarId { get; set; } public string LicensePlate { get; set; } public string Make { get; set; } public string Model { get; set; } public string State { get; set; } }
三.繼承
EF 模型中的繼承用於控制如何在資料庫中表示實體類中的繼承, 按照約定,由資料庫提供程式決定如何在資料庫中表示繼承。有關如何使用關係資料庫提供程式處理它,請查看”繼承關係資料庫“。如果模型中明確包含兩個或多個繼承類型,EF將僅設置繼承。EF 不會掃描的基類或派生類型,可以在模型中包含類型,通過公開DbSet 繼承層次結構中每個類型。不能使用數據註釋來配置繼承。
3.1 約定
下麵示例中,有二個實體,通過公開Dbset類型,預設約定繼承,如下所示:
class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<RssBlog> RssBlogs { get; set; } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } } public class RssBlog : Blog { public string RssUrl { get; set; } }
使用EF基於數據模型(Blog和RssBlog實體)創建資料庫。生成後,兩個實體合併到一個Blogs表中,如下所示:
3.2 Fluent API
如果您不想公開DbSet對於層次結構中的一個或多個實體,您可以使用Fluent API確保它們包含在模型中。如果您不依賴約定,則可以使用明確指定基類型HasBaseType
。
class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<RssBlog>().HasBaseType<Blog>(); } }
3.3 discriminator隱藏屬性
上面3.1示例中,創建了discriminator辨別者隱藏屬性,是基於base entity的層級。因為它是模型中的一個屬性,所以可以像配置其他屬性一樣配置它。例如,要設置預設情況下的最大長度。
modelBuilder.Entity<Blog>() .Property("Discriminator") .HasMaxLength(200);
discriminator鑒別器也可以映射到實體中的實際CLR屬性
class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasDiscriminator<string>("BlogType"); } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } //discriminator public string BlogType { get; set; } } public class RssBlog : Blog { public string RssUrl { get; set; } }
參考文獻:
官方文檔:EF索引