一.索引
索引是許多數(shù)據(jù)存儲(chǔ)中的常見(jiàn)概念。雖然它們?cè)跀?shù)據(jù)存儲(chǔ)中的實(shí)現(xiàn)可能會(huì)有所不同,但它們可用于更有效地基于列(或列集)進(jìn)行查找。按照約定,用作外鍵每個(gè)屬性 (或組的屬性) 會(huì)自動(dòng)創(chuàng)建索引。無(wú)法使用數(shù)據(jù)注釋創(chuàng)建索引。
1.1 非唯一索引
Fluent API 在單個(gè)屬性上指定索引。默認(rèn)情況下,索引是非唯一的。如下代碼示例在Blogs表上創(chuàng)建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 復(fù)合索引
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基于數(shù)據(jù)模型(People)創(chuàng)建數(shù)據(jù)表。在Migration中生成了索引的代碼, 以及查看數(shù)據(jù)庫(kù)People表的索引(官方文檔中暫沒(méi)有看到提供索引包含列設(shè)置)如下所示:
name: "IX_People_FirstName_LastName",
table: "People",
columns: new[] { "FirstName", "LastName" });

二.備用鍵
除主鍵之外,備用鍵用作每個(gè)實(shí)體實(shí)例的備用唯一標(biāo)識(shí)符(跟主鍵一樣具有唯一約束)。備用鍵可以用作關(guān)系的目標(biāo)。當(dāng)使用關(guān)系數(shù)據(jù)庫(kù)時(shí),這映射到備用鍵列上的唯一索引/約束的概念以及引用列的一個(gè)或多個(gè)外鍵約束。系統(tǒng)通常會(huì)在需要時(shí)為你引入備用鍵,你無(wú)需手動(dòng)配置它們。不能使用數(shù)據(jù)注釋配置備用鍵。
2.1 約定
按照約定,系統(tǒng)將在識(shí)別屬性(不是主鍵)時(shí)為你引入備用鍵,充當(dāng)關(guān)系的目標(biāo)。如下面代碼所示:
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中創(chuàng)建BlogUrl外建字段
.HasForeignKey(p => p.BlogUrl)
//Blog中設(shè)置唯一約束備份鍵
.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; }
}
上面主體實(shí)體Blog中Url屬性作為備用鍵,創(chuàng)建了AK_Blogs_Url唯一非聚集索引。在依賴(lài)實(shí)體Post中創(chuàng)建了BlogUrl外鍵字段, 使用EF基于數(shù)據(jù)模型(Blog和Post實(shí)體)創(chuàng)建數(shù)據(jù)庫(kù),如下圖所示。

2.2 Fluent API
可以使用Fluent API將單個(gè)屬性配置為備用鍵。
class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
//配置備用鍵(唯一非聚集索引)
.HasAlternateKey(c => c.LicensePlate);
// 創(chuàng)建復(fù)合備用鍵
// 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 模型中的繼承用于控制如何在數(shù)據(jù)庫(kù)中表示實(shí)體類(lèi)中的繼承, 按照約定,由數(shù)據(jù)庫(kù)提供程序決定如何在數(shù)據(jù)庫(kù)中表示繼承。有關(guān)如何使用關(guān)系數(shù)據(jù)庫(kù)提供程序處理它,請(qǐng)查看”繼承關(guān)系數(shù)據(jù)庫(kù)“。如果模型中明確包含兩個(gè)或多個(gè)繼承類(lèi)型,EF將僅設(shè)置繼承。EF 不會(huì)掃描的基類(lèi)或派生類(lèi)型,可以在模型中包含類(lèi)型,通過(guò)公開(kāi)DbSet 繼承層次結(jié)構(gòu)中每個(gè)類(lèi)型。不能使用數(shù)據(jù)注釋來(lái)配置繼承。
3.1 約定
下面示例中,有二個(gè)實(shí)體,通過(guò)公開(kāi)Dbset類(lèi)型,默認(rèn)約定繼承,如下所示:
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基于數(shù)據(jù)模型(Blog和RssBlog實(shí)體)創(chuàng)建數(shù)據(jù)庫(kù)。生成后,兩個(gè)實(shí)體合并到一個(gè)Blogs表中,如下所示:


3.2 Fluent API
如果您不想公開(kāi)DbSet對(duì)于層次結(jié)構(gòu)中的一個(gè)或多個(gè)實(shí)體,您可以使用Fluent API確保它們包含在模型中。如果您不依賴(lài)約定,則可以使用明確指定基類(lèi)型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示例中,創(chuàng)建了discriminator辨別者隱藏屬性,是基于base entity的層級(jí)。因?yàn)樗悄P椭械囊粋€(gè)屬性,所以可以像配置其他屬性一樣配置它。例如,要設(shè)置默認(rèn)情況下的最大長(zhǎng)度。
modelBuilder.Entity<Blog>()
.Property("Discriminator")
.HasMaxLength(200);
discriminator鑒別器也可以映射到實(shí)體中的實(shí)際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; }
}
參考文獻(xiàn):
官方文檔:EF索引