我看过一些书(例如, 编程实体框架代码首先是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; } }
编辑:
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类,则将导致堆栈溢出。这意味着我们应该有一个单向引用。(?)我们如何确定应删除哪一个导航属性?
License
User
集合和引用作为导航属性之间存在明显区别。引用 是 一个实体。集合 包含 实体。这意味着初始化集合对业务逻辑而言 毫无意义 :它没有定义实体之间的关联。设置参考确实如此。
因此,是否初始化或初始化嵌入式列表完全是一个优先事项。
至于“如何”,有些人喜欢延迟初始化:
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集合的对象(暂不加载)。检查集合是否已加载需要以下代码:
Addresses
var user = users.First(); var isLoaded = context.Entry(user).Collection(c => c.Addresses).IsLoaded;
如果未初始化集合,null则将执行简单检查。因此,当选择性显式加载是编码实践的重要组成部分时,即…
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关联也是如此。如果Address要User在其构造函数中初始化,则User.Addresses不会填充!
Licence
User.License
Address
User.Addresses
实体框架核心
实体框架核心中的关系修正(在撰写本文时为2.1)不受构造函数中初始化的参考导航属性的影响。也就是说,当分别从数据库中提取用户和地址时,将填充导航属性。 然而,延迟加载并 没有 覆盖初始化参考导航性能。
在EF核心3中,初始化参考导航属性会阻止其Include正常工作。
Include
因此,总之,同样在EF-core中,在构造函数中初始化参考导航属性可能会造成麻烦。不要这样 无论如何,这没有任何意义。