實體類型
在您的內容中包含類型的 DbSet 表示它包含在 EF Core 的模型中;我們通常會將這類類型 稱為實體 。 EF Core 可以從資料庫讀取和寫入實體實例,而且如果您使用關係資料庫,EF Core 可以透過移轉為實體建立資料表。
在模型中包括類型
依照慣例,在內容上的 DbSet 屬性中公開的類型會以實體的形式包含在模型中。 方法中指定的 OnModelCreating
實體類型也包含在內,以及遞迴探索其他探索實體類型的導覽屬性所找到的任何類型。
在下列程式碼範例中,會包含所有類型:
Blog
包含 ,因為它會在內容上的 DbSet 屬性中公開。Post
因為透過導覽屬性探索到Blog.Posts
它,所以會包含它。AuditEntry
因為它在 中OnModelCreating
指定。
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AuditEntry>();
}
}
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; }
}
public class AuditEntry
{
public int AuditEntryId { get; set; }
public string Username { get; set; }
public string Action { get; set; }
}
從模型排除類型
如果您不想在模型中包含類型,則可以將其排除:
[NotMapped]
public class BlogMetadata
{
public DateTime LoadedFromDatabase { get; set; }
}
從移轉排除
有時候,在多個 DbContext
類型中對應相同的實體類型會很有用。 使用系結內容時 ,這尤其如此,每個限定內容 通常會有不同的 DbContext
類型。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<IdentityUser>()
.ToTable("AspNetUsers", t => t.ExcludeFromMigrations());
}
使用此組態移轉不會建立 AspNetUsers
資料表,但仍 IdentityUser
包含在模型中,而且可以正常使用。
如果您需要再次使用移轉開始管理資料表,則應該在未排除的位置 AspNetUsers
建立新的移轉。 下一個移轉現在會包含對資料表所做的任何變更。
資料表名稱
依照慣例,每個實體類型都會設定為對應至與公開實體之 DbSet 屬性同名的資料庫資料表。 如果指定的實體不存在 DbSet,則會使用類別名稱。
您可以手動設定資料表名稱:
[Table("blogs")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
資料表架構
使用關係資料庫時,資料表會依慣例在資料庫的預設架構中建立。 例如,Microsoft SQL Server 將使用 dbo
架構(SQLite 不支援架構)。
您可以將資料表設定為在特定架構中建立,如下所示:
[Table("blogs", Schema = "blogging")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
您也可以使用 Fluent API 在模型層級定義預設架構,而不是為每個資料表指定架構:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("blogging");
}
請注意,設定預設架構也會影響其他資料庫物件,例如序列。
檢視對應
實體類型可以使用 Fluent API 對應至資料庫檢視。
注意
EF 會假設參考的檢視已存在於資料庫中,因此不會在移轉中自動建立檢視。
modelBuilder.Entity<Blog>()
.ToView("blogsView", schema: "blogging");
對應至檢視將會移除預設資料表對應,但實體類型也可以明確地對應至資料表。 在此情況下,查詢對應將用於查詢,而資料表對應將用於更新。
提示
若要使用記憶體內部提供者測試對應至檢視的無索引鍵實體類型,請透過 ToInMemoryQuery 將其對應至查詢。 如需詳細資訊,請參閱記憶體內部提供者檔 。
資料表值函式對應
可以將實體類型對應至資料表值函式 (TVF),而不是資料庫中的資料表。 為了說明這一點,讓我們定義另一個實體,代表具有多個文章的部落格。 在此範例中,實體是 無 索引鍵的,但不需要。
public class BlogWithMultiplePosts
{
public string Url { get; set; }
public int PostCount { get; set; }
}
接下來,在資料庫中建立下列資料表值函式,只傳回具有多個文章的部落格,以及與每個部落格相關聯的文章數目:
CREATE FUNCTION dbo.BlogsWithMultiplePosts()
RETURNS TABLE
AS
RETURN
(
SELECT b.Url, COUNT(p.BlogId) AS PostCount
FROM Blogs AS b
JOIN Posts AS p ON b.BlogId = p.BlogId
GROUP BY b.BlogId, b.Url
HAVING COUNT(p.BlogId) > 1
)
現在,實體 BlogWithMultiplePosts
可以透過下列方式對應至此函式:
modelBuilder.Entity<BlogWithMultiplePosts>().HasNoKey().ToFunction("BlogsWithMultiplePosts");
注意
若要將實體對應至資料表值函式,函式必須是無參數的。
傳統上,實體屬性會對應到 TVF 所傳回的相符資料行。 如果 TVF 傳回的資料行名稱與實體屬性不同,則可以使用 HasColumnName
方法設定實體的資料行,就像對應至一般資料表一樣。
當實體類型對應至資料表值函式時,查詢:
var query = from b in context.Set<BlogWithMultiplePosts>()
where b.PostCount > 3
select new { b.Url, b.PostCount };
產生下列 SQL:
SELECT [b].[Url], [b].[PostCount]
FROM [dbo].[BlogsWithMultiplePosts]() AS [b]
WHERE [b].[PostCount] > 3
資料表批註
您可以設定在資料庫資料表上設定的任意文字批註,讓您在資料庫中記錄架構:
[Comment("Blogs managed on the website")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
共用類型實體類型
使用相同 CLR 類型的實體類型稱為共用類型實體類型。 除了 CLR 類型之外,這些實體類型還需要以唯一的名稱進行設定,每當使用共用類型實體類型時,都必須提供此名稱。 這表示必須使用呼叫實 Set
作對應的 DbSet
屬性。
internal class MyContext : DbContext
{
public DbSet<Dictionary<string, object>> Blogs => Set<Dictionary<string, object>>("Blog");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.SharedTypeEntity<Dictionary<string, object>>(
"Blog", bb =>
{
bb.Property<int>("BlogId");
bb.Property<string>("Url");
bb.Property<DateTime>("LastUpdated");
});
}
}