一尘不染

EF codefirst:我应该初始化导航属性吗?

c#

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

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时会初始化类的导航属性,例如:

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

问题2:在第二种方法中,如果License类也引用了User类,则将导致堆栈溢出。这意味着我们应该有一个单向引用。(?)我们如何确定应删除哪一个导航属性?


阅读 394

收藏
2020-05-19

共1个答案

一尘不染

集合:没关系。

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

因此,是否初始化或初始化嵌入式列表完全是一个优先事项。

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

private ICollection<Address> _addresses;

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

它防止了空引用异常,因此它有助于单元测试和操作集合,但同时也避免了不必要的初始化。当一个类具有相对较多的集合时,后者可能会有所作为。缺点是,它需要相对较多的管道,特别是。与未初始化的自动属性相比。同样,C#中空传播运算符的出现使初始化集合属性的迫切性降低了。

…除非应用了显式加载

唯一的问题是,初始化集合使得很难检查实体框架是否已加载集合。如果初始化集合,则类似…的语句

var users = context.Users.ToList();

…将创建User具有空的,非null Addresses集合的对象(暂不加载)。检查集合是否已加载需要以下代码:

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

如果未初始化集合,null则将执行简单检查。因此,当选择性显式加载是编码实践的重要组成部分时,即…

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

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

参考属性:不要

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

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

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

实体框架核心

实体框架核心中的关系修正(在撰写本文时为2.1)不受构造函数中初始化的参考导航属性的影响。也就是说,当分别从数据库中提取用户和地址时,将填充导航属性。
然而,延迟加载并 没有 覆盖初始化参考导航性能。

在EF核心3中,初始化参考导航属性会阻止其Include正常工作。

因此,总之,同样在EF-core中,在构造函数中初始化参考导航属性可能会造成麻烦。不要这样 无论如何,这没有任何意义。

2020-05-19