我有一个ASP.NET MVC应用程序,它利用实体框架来处理数据层。
在我的一种方法中,我检索产品的季节性可用性数据,然后检索产品的最佳税率。
public ProductList FetchProductSearchList(ProductSearchCriteria criteria)
{
...
var avail = ProductAvailabilityTemplate.Get(criteria.ProductID);
...
var tr = TaxRate.BestMatchFor(criteria.ProductID, criteria.TaxCode);
...
}
在ProductAvailabilityTemplate.Get的数据层中,我一直在优化LINQ代码的性能。特别是,我设置ctx.ObjectContext.ContextOptions.LazyLoadingEnabled = false;
以防止EF加载某些实体(通过导航属性),在这种情况下我不需要。
但是,一旦进行了此更改,我发现我的TaxRates未完全加载,因为我的Tax数据层代码中的ctx.ObjectContext.ContextOptions.LazyLoadingEnabled
仍为false。这意味着没有加载通过导航属性链接到TaxRate的实体。
要解决这个问题,我只需在Tax数据层方法中设置ctx.ObjectContext.ContextOptions.LazyLoadingEnabled = true;
,但我担心无关的更改可能会导致这样的问题。您似乎无法安全地禁用一个功能的延迟加载,而不会影响之后调用的操作。我很想删除所有的导航属性,禁用延迟加载,并使用良好的老式连接来加载我需要的每个数据层调用,不多也不少。
欢迎任何建议。
答案 0 :(得分:2)
当我开始使用EF时,我喜欢延迟加载,但过了一段时间后,我意识到它影响了性能,因为它有效地禁用了连接并在单独的查询中提取所有子数据,即使您需要一次性使用它。 / p>
所以现在我宁愿使用Includes来热切地加载我感兴趣的子实体。你也可以这样做有点动态,例如提供 includeDetails 参数:
public IEnumerable<Customer> LoadCustomersStartingWithName(string name, bool includeDetails)
{
using (var db = new MyContext())
{
var customers = db.Customers;
if (includeDetails)
customers = customers.Include(x => x.Orders).Include(x => x.ContactPersons);
customers = customers.Where(x => x.Name.StartsWith(name));
return customers;
}
}
要使代码在EF6中运行,您还需要包含
using System.Data.Entity;
位于班级的顶部
答案 1 :(得分:2)
这是一种权衡:
延迟加载
virtual
属性与代理)DbContext
在所有数据访问期间保持更长时间。急切加载
DbContexts
FWIW,我通常在启用了延迟加载的情况下完成原型工作,使软件处于可证明状态,一旦数据访问模式稳定,然后关闭延迟加载并明确移动到Include
d引用。检查空引用的一些单元测试在这一点上也会产生奇迹。我不愿意提供仍然启用了延迟加载的生产系统,因为存在一个非确定性元素(例如难以完全测试),并且需要返回数据库以获取更多数据会损害性能。
无论哪种方式,我都不会关闭所有导航并进行显式连接 - 您正在失去ORM提供的导航功能。当您退出延迟加载时,只需使用适用的Includes
明确定义要加载的实体