Entity framework 如何在实体框架中处理深层关系树?

Entity framework 如何在实体框架中处理深层关系树?,entity-framework,lazy-loading,eager-loading,Entity Framework,Lazy Loading,Eager Loading,在我的模型设计中,我有一个非常深的关系树,即根实体包含一个实体集合,该集合包含更多的其他实体集合,这些实体集合包含更多的集合,并且在一个on。。。我开发了一个业务层,其他开发人员必须使用它来执行操作,包括获取/保存数据 然后,我在思考应对这种情况的最佳策略是什么。我不能允许在检索实体时,EF解析所有依赖关系树,因为它将以大量无用的连接结束(无用,因为我可能不需要下一级的数据) 如果我禁用延迟加载并对需要的内容强制执行快速加载,它将按预期工作,但是如果其他开发人员调用child.Parent.I

在我的模型设计中,我有一个非常深的关系树,即根实体包含一个实体集合,该集合包含更多的其他实体集合,这些实体集合包含更多的集合,并且在一个on。。。我开发了一个业务层,其他开发人员必须使用它来执行操作,包括获取/保存数据

然后,我在思考应对这种情况的最佳策略是什么。我不能允许在检索实体时,EF解析所有依赖关系树,因为它将以大量无用的连接结束(无用,因为我可能不需要下一级的数据)

  • 如果我禁用延迟加载对需要的内容强制执行快速加载,它将按预期工作,但是如果其他开发人员调用
    child.Parent.Id
    而不是
    child.ParentId
    尝试做一些新的事情(比如新的需求或功能在设计阶段没有考虑),如果不包括该依赖项,它将得到一个
    NullReferenceException
    ,这是错误的。。。但这将是一个“快速错误”,可以立即修复

  • 如果我启用延迟加载,则每次访问数据库时,访问
    child.Parent.Id
    而不是
    child.ParentId
    将以对数据库的独立查询结束。它不会失败,但更糟糕的是,没有错误,只有性能下降,所有代码都应该检查

我对这两种解决方案都不满意

  • 我不喜欢有包含null或空集合的实体,但实际上,这不是真的

  • 我不喜欢让EF在任何时候对DB执行任意查询。如果可能的话,我想在一次拍摄中获得所有信息

因此,我提出了几种可能的解决方案,包括禁用延迟加载强制执行快速加载,但不确定哪一种更好:

  • 我可以创建一个
    EntityBase
    类,该类包含表中的数据,而不包含集合,因此无法访问它们。对于包含这些关系的具体实现,问题在于您没有太多的灵活性,因为C#不允许多重继承

  • 我可以创建接口来“屏蔽”隐藏在该方法调用时不可用的属性的对象。例如,如果我有一个
    User.Roles
    属性,为了向所有用户显示一个网格,我不需要解析
    .Roles
    属性,因此我可以创建一个不包含此类属性的接口“IUserData”

但是我不知道如果这额外的工作值得,也许一个fast
NullReferenceException
指示“此属性尚未加载”就足够了

如果属性是虚拟的且未被重写/设置,是否可以引发特定的异常类型

你用什么方法

谢谢。

在我看来,您需要了解他们在访问数据时所做的事情,以及数据可能带来的性能影响,这可能会导致不必要的复杂API,其中包含大量帮助器类、基类、接口等

如果开发人员使用
user.MiddleName.Trim()
并且
MiddleName
null
时,他会得到一个
NullReferenceException
并出错,或者没有检查
null
或者没有确保
MiddleName
设置为一个值。当他访问
user.Roles
并获得
NullReferenceException
时也是如此:他没有检查
null
,或者没有调用加载用户
角色的API的适当方法

我想说:解释导航属性是如何工作的,它们必须被明确地请求,如果开发人员不遵守规则,应用程序就会崩溃。他需要理解错误并改正它

作为帮助,您可以在API中以某种方式显式加载相关数据,例如使用以下方法:

public User GetUser(int userId);
public User GetUserWithRoles(int userId);
或:

您还可以利用显式加载而不是延迟加载来强制开发人员在希望加载导航属性而不仅仅是访问该属性时调用方法

补充两点:

…延迟加载。。。每次都将以对数据库的独立查询结束 它是可访问的

“…尚未加载”以完成此操作。如果导航属性已在同一上下文中加载,则再次访问该属性不会触发对数据库的查询

如果可能的话,我想在一次拍摄中获得所有信息


多个查询不一定会比一个包含大量
Include
s的查询的性能差。事实上,复杂的急加载使得实体物化非常耗时,并且比多个延迟或显式加载查询慢。(一个查询的性能提高了50倍,将其从一个包含
Include
s的单个查询更改为不包含
Include
的1000多个查询)其精髓是:在不测量性能的情况下,您无法可靠地预测特定情况下的最佳加载策略(如果在这种情况下性能很重要)。

从您使用的示例来看,您似乎主要是从树的底部向上走,对吗?不完全是,这只是一个示例。您为什么要问这个问题?这是一个非常好的答案。我喜欢那种包含要加载的表达式列表的方法。您在“复杂的渴望的loding”中提出了一个很好的观点问题,我会仔细阅读这些链接。非常感谢。
public User GetUser(int userId, params Expression<Func<User,object>>[] includes);
var userWithoutRoles = layer.GetUser(1);
var userWithRoles = layer.GetUser(2, u => u.Roles);