在Entity Framework Core中编写实体POCO类的正确方法是什么? [英] What is a proper way of writing entity POCO classes in Entity Framework Core?

查看:105
本文介绍了在Entity Framework Core中编写实体POCO类的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

默认情况下,EF Core具有代码优先的心态",即应该以代码优先的方式使用,即使支持数据库优先的方法,它也仅是对产品的反向工程而已.现有数据库并为其创建代码优先表示.我的意思是,用手动"代码(代码优先)创建的模型(POCO类),并通过数据库(通过Scaffold-DbContext命令)生成的模型应该是相同的.

EF Core has a "code first mentality" by default, i.e. it is supposed to be used in a code-first manner, and even though database-first approach is supported, it is described as nothing more than reverse-engineering the existing database and creating code-first representation of it. What I mean is, the model (POCO classes) created in code "by hand" (code-first), and generated from the database (by Scaffold-DbContext command), should be identical.

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

Surprisingly, official EF Core docs demonstrate significant differences. Here is an example of creating the model in code: https://ef.readthedocs.io/en/latest/platforms/aspnetcore/new-db.html And here is the example of reverse-engineering it from existing database: https://ef.readthedocs.io/en/latest/platforms/aspnetcore/existing-db.html

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

This is the entity class in first case:

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; }
}

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

and this is the entity class in second case:

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类.它在文档的任何地方都显示(从数据库生成的示例除外).不过,第二个示例有一些补充:

The first example is a very simple, quite obvious POCO class. It is shown everywhere in the documentation (except for the examples generated from database). The second example though, has some additions:

  • 类被声明为 partial (即使没有地方可以看到它的另一个 partial 定义).
  • 导航属性的类型为 ICollection< T> ,而不只是List< T>.
  • 导航属性被初始化为 new HashSet< T>().在代码优先的示例中没有这种初始化.
  • 导航属性被声明为虚拟.
  • 生成的上下文类中的
  • DbSet成员也是虚拟.
  • Class is declared partial (even though there's nowhere to be seen another partial definition of it).
  • Navigation property is of type ICollection< T >, instead of just List< T >.
  • Navigation property is initialized to new HashSet< T >() in the constructor. There is no such initialization in code-first example.
  • Navigation property is declared virtual.
  • DbSet members in a generated context class are also virtual.

我已经尝试从数据库中构建模型(撰写本文时为最新工具),并且它完全按照所示方式生成实体,因此这不是过时的文档问题.因此,官方工具会生成不同的代码,并且官方文档建议编写不同的(琐碎的)代码-无需局部类,虚拟成员,构造初始化等.

I've tried scaffolding the model from database (latest tooling as of this writing) and it generates entities exactly as shown, so this is not an outdated documentation issue. So the official tooling generates different code, and the official documentation suggests writing different (trivial) code - without partial class, virtual members, construction initialization, etc.

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

My question is, trying to build the model in code, how should I write my code? I like using ICollection instead of List because it is more generic, but other than that, I'm not sure whether I need to follow docs, or MS tools? Do I need to declare them as virtual? Do I need to initialize them in a constructor? etc...

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

I know from the old EF times that virtual navigation properties allow lazy loading, but it is not even supported (yet) in EF Core, and I don't know of any other uses. Maybe it affects performance? Maybe tools try to generate future-proof code, so that when lazy-loading will be implemented, the POCO classes and context will be able to support it? If so, can I ditch them as I don't need lazy loading (all data querying is encapsulated in a repo)?

很快,请帮助我理解为什么会有区别,以及在代码中构建模型时应该使用哪种样式?

Shortly, please help me understand why is the difference, and which style should I use when building the model in code?

推荐答案

我尝试对您提到的每一点做一个简短的回答

I try to give a short answer to each point you mentioned

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

  • partial classes are specially useful for tool-generated code. Suppose you want to implement a model-only derived property. For code first, you would just do it, wherever you want. For database first, the class file will be re-written if you update your model. So if you want to keep your extension code, you want to place it in a different file outside the managed model - this is where partial helps you to extend the class without tweaking the auto-generated code by hand.

ICollection绝对是一个合适的选择,即使对于代码优先.如果没有排序语句,您的数据库可能将始终不支持定义的顺序.

ICollection is definitely a suitable choice, even for code first. Your database probably won't support a defined order anyway without a sorting statement.

构造函数初始化至少很方便...假设您有一个空的数据库收集集合,或者根本没有加载该属性.如果没有构造函数,则必须在代码中的任意点显式处理null情况.我现在无法回答是选择List还是HashSet.

Constructor initialization is a convenience at least... suppose you have either an empty collection database-wise or you didn't load the property at all. Without the constructor you have to handle null cases explicitely at arbitrary points in code. Whether you should go with List or HashSet is something I can't answer right now.

virtual启用数据库实体的代理创建,这可以帮助两件事:如前所述,延迟加载和更改跟踪.代理对象可以使用设置器立即跟踪对虚拟属性的更改,而上下文中的普通对象需要在SaveChanges上进行检查.在某些情况下,这可能会更有效(并非通常如此).

virtual enables proxy creation for the database entities, which can help with two things: Lazy Loading as you already mentioned and change tracking. A proxy object can track changes to virtual properties immediately with the setter, while normal objects in the context need to be inspected on SaveChanges. In some cases, this might be more efficient (not generally).

virtual IDbSet上下文条目使单元测试的测试模型上下文更容易设计.其他用例也可能存在.

virtual IDbSet context entries allow easier design of testing-mockup contexts for unit tests. Other use cases might also exist.

这篇关于在Entity Framework Core中编写实体POCO类的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆