默认情况下,EF Core 具有“代码优先的心态”,即它应该以代码优先的方式使用,即使支持数据库优先的方法,它也被描述为无非是对现有数据库并创建它的代码优先表示。我的意思是,“手动”(代码优先)在代码中创建的模型(POCO 类)和从数据库(通过 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(即使在任何地方都看不到它的另一个partial定义)。
- 导航属性是 ICollection< T > 类型,而不仅仅是 List< T >。
- 导航属性在构造函数中被初始化为new HashSet< T >()。在代码优先示例中没有这样的初始化。
- 导航属性被声明为虚拟。
- 生成的上下文类中的 DbSet 成员也是虚拟的。
我已经尝试从数据库(撰写本文时的最新工具)构建模型,它生成的实体与所示的完全相同,因此这不是一个过时的文档问题。因此官方工具生成不同的代码,官方文档建议编写不同的(琐碎的)代码——没有部分类、虚拟成员、构造初始化等。
我的问题是,尝试用代码构建模型时,我应该如何编写代码?我喜欢使用 ICollection 而不是 List 因为它更通用,但除此之外,我不确定我是否需要遵循文档或 MS 工具?我需要将它们声明为虚拟的吗?我需要在构造函数中初始化它们吗?等等……
我从旧的 EF 时代就知道虚拟导航属性允许延迟加载,但 EF Core 甚至(目前)还不支持它,而且我不知道任何其他用途。也许它会影响性能?也许工具会尝试生成面向 future 的代码,以便在实现延迟加载时,POCO 类和上下文能够支持它?如果是这样,我是否可以放弃它们,因为我不需要延迟加载(所有数据查询都封装在一个 repo 中)?
请尽快帮助我理解为什么会有所不同,以及在代码中构建模型时应该使用哪种样式?
最佳答案
我尽量对你提到的每一点给出一个简短的回答
partial
类对于工具生成的代码特别有用。假设您要实现一个仅限模型的派生属性。对于代码优先,您可以随心所欲地进行。对于数据库优先,如果更新模型,类文件将被重写。所以如果你想保留你的扩展代码,你想把它放在托管模型之外的不同文件中 - 这是partial
帮助你扩展类的地方,而无需手动调整自动生成的代码.ICollection
绝对是一个合适的选择,即使对于代码优先。如果没有排序语句,您的数据库可能无论如何都不支持定义的顺序。构造函数初始化至少很方便...假设您有一个空的数据库集合,或者您根本没有加载该属性。如果没有构造函数,您必须在代码中的任意点显式处理
null
情况。您应该使用List
还是HashSet
我现在无法回答。virtual
支持为数据库实体创建代理,这可以帮助完成两件事:您已经提到的延迟加载和更改跟踪。代理对象可以使用 setter 立即跟踪对虚拟属性的更改,而需要在SaveChanges
上检查上下文中的普通对象。在某些情况下,这可能更有效(通常不是)。虚拟 IDbSet
上下文条目允许更轻松地设计用于单元测试的测试模型上下文。其他用例也可能存在。
关于c# - 在 Entity Framework Core 中编写实体 POCO 类的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38954108/