实体类型

在上下文中包含一种类型的 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; }
}

从迁移中排除

备注

EF Core 5.0 中引入了从迁移中排除表的功能。

有时在多个类型中映射相同的实体类型会很有用 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");

映射到视图将删除默认表映射,但从 EF 5.0 开始,实体类型也可以显式映射到表。 在这种情况下,查询映射将用于查询,表映射将用于更新。

提示

若要测试使用内存中提供程序映射到视图的实体类型,请通过将它们映射到查询 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

表注释

您可以设置对数据库表设置的任意文本注释,以允许您在数据库中记录架构:

备注

EF Core 5.0 中引入了通过数据批注设置注释。

[Comment("Blogs managed on the website")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}