在Entity Framework Core中编写实体POCO类的正确方法是什么?

时间:2016-08-15 11:20:35

标签: c# .net entity-framework asp.net-core entity-framework-core

默认情况下,EF Core具有“代码优先心态”,即它应该以代码优先的方式使用,即使支持数据库优先方法,它也只能进行逆向工程。现有数据库并创建它的代码优先表示。我的意思是,在代码“手工”(代码优先)中创建并从数据库(通过Scaffold-DbContext命令)生成的模型(POCO类)应该是相同的。

令人惊讶的是,官方EF Core文档显示出显着差异。以下是在代码中创建模型的示例:https://ef.readthedocs.io/en/latest/platforms/aspnetcore/new-db.html以下是从现有数据库对其进行逆向工程的示例:https://ef.readthedocs.io/en/latest/platforms/aspnetcore/existing-db.html

这是第一种情况下的实体类:

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 int BlogId { get; set; }
    public Blog Blog { get; set; }
}

这是第二种情况下的实体类:

public partial class Blog
{
    public Blog()
    {
        Post = new HashSet<Post>();
    }

    public int BlogId { get; set; }
    public string Url { get; set; }

    public virtual ICollection<Post> Post { get; set; }
}

第一个例子是一个非常简单,非常明显的POCO类。它在文档中随处可见(除了从数据库生成的示例)。第二个例子有一些补充:

  • 类被声明为 partial (即使无处可见其他部分定义)。
  • 导航属性的类型为 ICollection&lt; T&gt; ,而不仅仅是List&lt; T&gt;。
  • 导航属性初始化为 new HashSet&lt;构造函数中的T&gt;()。在代码优先的例子中没有这样的初始化。
  • 导航属性声明为虚拟
  • 生成的上下文类中的DbSet成员也是虚拟

我尝试过从数据库中构建模型(截至本文撰写时的最新工具)并且它完全按照所示生成实体,因此这不是一个过时的文档问题。因此官方工具生成不同的代码,官方文档建议编写不同的(普通的)代码 - 没有部分类,虚拟成员,构造初始化等。

我的问题是,尝试在代码中构建模型,我应该如何编写代码?我喜欢使用ICollection而不是List,因为它更通用,但除此之外,我不确定我是否需要遵循文档或MS工具?我需要将它们声明为虚拟吗?我是否需要在构造函数中初始化它们?等...

我从旧的EF时代知道虚拟导航属性允许延迟加载,但在EF Core中甚至不支持它(我),我不知道任何其他用途。也许它会影响性能?也许工具试图生成面向未来的代码,这样当实现延迟加载时,POCO类和上下文将能够支持它吗?如果是这样,我可以抛弃它们,因为我不需要延迟加载(所有数据查询都封装在一个回购中)?

很快,请帮助我理解为什么不同,在代码中构建模型时应该使用哪种样式?

1 个答案:

答案 0 :(得分:13)

我试着简单回答你提到的每一点

  • partial类对工具生成的代码特别有用。假设您要实现仅模型派生属性。对于代码优先,您只需要在任何地方执行此操作。对于数据库优先,如果更新模型,将重写类文件。因此,如果您想保留扩展代码,则需要将其放在托管模型之外的其他文件中 - 这是partial帮助您扩展类而无需手动调整自动生成代码的地方。

  • ICollection绝对是一个合适的选择,即使是代码优先。如果没有排序声明,您的数据库可能不会支持已定义的订单。

  • 构造函数初始化至少是一种方便...假设您有一个数据库方式的空集合,或者根本没有加载该属性。如果没有构造函数,则必须在代码中的任意点处明确处理null个案例。您是否应该使用ListHashSet是我现在无法回答的问题。

  • virtual可以为数据库实体创建代理,这可以帮助您完成两件事:如您所述的延迟加载和更改跟踪。代理对象可以使用setter立即跟踪虚拟属性的更改,而上下文中的普通对象需要在SaveChanges上进行检查。在某些情况下,这可能更有效(通常不是)。

  • virtual IDbSet上下文条目可以更轻松地设计单元测试的测试模型上下文。其他用例也可能存在。