entity-framework - 您如何处理 Entity Framework 中的深层关系树?

标签 entity-framework lazy-loading eager-loading

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

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

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

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

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

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

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

因此,我想出了几个可能的解决方案,包括禁用延迟加载强制预先加载,但不确定哪个更好:

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

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

但我不认为这项额外的工作是否值得,也许一个快速的 NullReferenceException 指示“此属性尚未加载”就足够了。

如果属性是虚拟的并且没有被覆盖/设置,是否可以抛出特定的异常类型?

你用什么方法?

谢谢。

最佳答案

在我看来你是trying to protect the developers从需要了解他们在访问数据时正在做什么以及它可能对性能产生什么影响 - 这可能会导致不必要的复杂 API,其中包含许多帮助类、基类、接口(interface)等。

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

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

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

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

或者:

public User GetUser(int userId, params Expression<Func<User,object>>[] includes);

可以调用:

var userWithoutRoles = layer.GetUser(1);
var userWithRoles = layer.GetUser(2, u => u.Roles);

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

补充两点:

...lazy loading ... will end in a standalone query to the DB each time it is accessed.

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

I would like to get all the information in one shoot if possible.

多个查询的性能不一定比具有大量 Include 的一个查询差。事实上复杂的预加载can lead to data multiplication on the wire并使实体实现非常耗时,并且比多个延迟或显式加载查询慢。 (Here is an example 通过将查询从使用 Include 的单个查询更改为不使用 Include 的 1000 多个查询,查询的性能提高了 50 倍。)Quintessence是:如果不衡量性能(如果性能在那种情况下很重要),则无法可靠地预测特定情况下的最佳加载策略。

关于entity-framework - 您如何处理 Entity Framework 中的深层关系树?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12236993/

相关文章:

entity-framework - 为什么 Entity Framework 缺少以 'Status' 结尾的表中的最后一个 s

asp.net-mvc-2 - 选择聚合时如何处理 Linq to NHibernate 的 Fetch 异常?

laravel-5.4 - laravel hydrateRaw/fromQuery 和带分页的预加载

c# - 如何在 LINQ 中使用表字段创建新的 DateTime where 条件

entity-framework - 从 dbset<t> 中选择某些字段

c# - Entity Framework 使用 Codefirst、通用存储库、工作单元模式保存多对多关系

java - 初始化惰性集合

javascript - Angular 延迟加载模块错误 - 'RouterModule.forRoot() called twice'

entity-framework - 具有所需关联的 Entity Framework 4.3