EF codefirst:我应该初始化导航属性吗? [英] EF codefirst : Should I initialize navigation properties?

查看:27
本文介绍了EF codefirst:我应该初始化导航属性吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过一些书(例如首先编写实体框架代码Julia Lerman)定义了他们的域类(POCO),而没有初始化导航属性,例如:

I had seen some books(e.g programming entity framework code first Julia Lerman) define their domain classes (POCO) with no initialization of the navigation properties like:

public class User
{
    public int Id { get; set; }
    public string UserName { get; set; }

    public virtual ICollection<Address> Address { get; set; }
    public virtual License License { get; set; }
}

一些其他书籍或工具(例如 Entity Framework Power Tools)在生成 POCO 时会初始化类的导航属性,例如:

some other books or tools (e.g Entity Framework Power Tools) when generates POCOs initializes the navigation properties of the the class, like:

public class User
{
    public User()
    {
        this.Addresses = new IList<Address>();
        this.License = new License();
    }
    public int Id { get; set; }
    public string UserName { get; set; }

    public virtual ICollection<Address> Addresses { get; set; }
    public virtual License License { get; set; }
}

Q1:哪个更好?为什么?利弊?

public class License
{
    public License()
    {
        this.User = new User();
    }
    public int Id { get; set; }
    public string Key { get; set; }
    public DateTime Expirtion { get; set; }

    public virtual User User { get; set; }
}

Q2:在第二种方法中,如果 `License` 类也有对 `User` 类的引用,则会出现堆栈溢出.这意味着我们应该有单向引用.(?)我们应该如何决定应该删除哪一个导航属性?

推荐答案

集合:没关系.

作为导航属性的集合和引用之间存在明显区别.引用一个实体.集合包含实体.这意味着初始化集合在业务逻辑方面毫无意义:它没有定义实体之间的关联.设置引用确实如此.

Collections: It doesn't matter.

There is a distinct difference between collections and references as navigation properties. A reference is an entity. A collections contains entities. This means that initializing a collection is meaningless in terms of business logic: it does not define an association between entities. Setting a reference does.

因此,是否或如何初始化嵌入列表纯粹是一个偏好问题.

So it's purely a matter of preference whether or not, or how, you initialize embedded lists.

至于如何",有些人更喜欢延迟初始化:

As for the "how", some people prefer lazy initialization:

private ICollection<Address> _addresses;

public virtual ICollection<Address> Addresses
{ 
    get { return this._addresses ?? (this._addresses = new HashSet<Address>());
}

它可以防止空引用异常,因此它有助于单元测试和操作集合,但它也可以防止不必要的初始化.当一个类有相对较多的集合时,后者可能会有所不同.缺点是它需要相对较多的管道,尤其是.与没有初始化的自动属性相比.此外,C# 中空传播运算符的出现使得初始化集合属性变得不那么紧迫了.

It prevents null reference exceptions, so it facilitates unit testing and manipulating the collection, but it also prevents unnecessary initialization. The latter may make a difference when a class has relatively many collections. The downside is that it takes relatively much plumbing, esp. when compared to auto properties without initialization. Also, the advent of the null-propagation operator in C# has made it less urgent to initialize collection properties.

...除非应用了显式加载

唯一的问题是初始化集合使得很难检查实体框架是否加载了集合.如果一个集合被初始化,一个语句像...

The only thing is that initializing collections makes it hard to check whether or not a collection was loaded by Entity Framework. If a collection is initialized, a statement like...

var users = context.Users.ToList();

...将创建具有空的、非空的 Addresses 集合的 User 对象(延迟加载除外).检查集合是否被加载需要像这样的代码...

...will create User objects having empty, not-null Addresses collections (lazy loading aside). Checking whether the collection is loaded requires code like...

var user = users.First();
var isLoaded = context.Entry(user).Collection(c => c.Addresses).IsLoaded;

如果集合没有初始化,一个简单的 null 检查就可以了.So when selective explicit loading is an important part of your coding practice, i.e. ...

If the collection is not initialized a simple null check will do. So when selective explicit loading is an important part of your coding practice, i.e. ...

if (/*check collection isn't loaded*/)
    context.Entry(user).Collection(c => c.Addresses).Load();

...不初始化集合属性可能更方便.

...it may be more convenient not to initialize collection properties.

引用属性是实体,因此为它们分配一个空对象是有意义的.

Reference properties are entities, so assigning an empty object to them is meaningful.

更糟糕的是,如果您在构造函数中启动它们,EF 不会在具体化您的对象或通过延迟加载时覆盖它们.在您主动替换它们之前,它们将始终具有初始值.更糟糕的是,您甚至可能最终将空实体保存在数据库中!

Worse, if you initiate them in the constructor, EF won't overwrite them when materializing your object or by lazy loading. They will always have their initial values until you actively replace them. Worse still, you may even end up saving empty entities in the database!

还有另一个效果:关系修复不会发生.关系修复是 EF 通过其导航属性连接上下文中所有实体的过程.当 UserLicence 分别加载时,仍然会填充 User.License ,反之亦然.当然,除非 License 在构造函数中初始化.对于 1:n 关联也是如此.如果 Address 将在其构造函数中初始化 User,则不会填充 User.Addresses

And there's another effect: relationship fixup won't occcur. Relationship fixup is the process by which EF connects all entities in the context by their navigation properties. When a User and a Licence are loaded separately, still User.License will be populated and vice versa. Unless of course, if License was initialized in the constructor. This is also true for 1:n associations. If Address would initialize a User in its constructor, User.Addresses would not be populated!

实体框架核心

实体框架核心(撰写本文时为 2.1)中的关系修复不受构造函数中初始化的引用导航属性的影响.即分别从数据库中拉取用户和地址时,填充导航属性.
但是,延迟加载不会覆盖初始化的参考导航属性.

Relationship fixup in Entity Framework core (2.1 at the time of writing) isn't affected by initialized reference navigation properties in constructors. That is, when users and addresses are pulled from the database separately, the navigation properties are populated.
However, lazy loading does not overwrite initialized reference navigation properties.

在 EF-core 3 中,初始化参考导航属性会阻止 Include 正常工作.

In EF-core 3, initializing a reference navigation property prevents Include from working properly.

所以,总而言之,同样在 EF-core 中,在构造函数中初始化引用导航属性可能会导致麻烦.不要这样做.反正没意义.

So, in conclusion, also in EF-core, initializing reference navigation properties in constructors may cause trouble. Don't do it. It doesn't make sense anyway.

这篇关于EF codefirst:我应该初始化导航属性吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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