![](/img/trans.png)
[英].NET Entity Framework code-first: navigation properties are not loaded
[英]Entity Framework code-first IQueryable navigation property
我在互联网上看到的大多数示例都将导航属性显示为ICollection
或直接List
实现。 它们通常是virtual
,以启用延迟加载。
但是,当您访问此类属性时,它将在内存中加载整个集合,并且如果您在它之后有一个子查询(即object.MyListProperty.Where(...)
),我注意到将为每个项目发出一个 SQL 查询在MyListProperty
。
我如何避免这种情况? 如果可能,我希望 list 属性之后的where
子句在 SQL 服务器上执行。 我可以使用IQueryable
导航属性吗? 这种情况有什么最佳实践吗?
我对最佳实践的建议是完全禁用延迟加载。 相反,强制调用者通过包含语句或使用投影急切地加载导航属性。
有 3rd 方产品支持包含过滤器,如这篇文章中所述: 如何过滤实体框架中的包含实体,但根据我的经验,这使所检索对象的下游处理进一步复杂化。 如果实体对象是在方法
X
之外加载的,因为方法X
无法确定导航属性是否已加载了正确的过滤器,方法X
通过重新查询它知道它需要的精确行开始。
using (var context = new MyDbContext())
{
context.Configuration.LazyLoadingEnabled = false;
// TODO: load your data
...
}
这样,只有在明确请求时才会加载记录。
当您想要访问IQueryable
以便延迟数据加载时,然后针对 DbContext实例而不是从对象进行这些查询。
Customer
有成千上万的事务,所以我们根本不希望它们被急切或延迟加载。using (var context = new MyDbContext())
{
context.Configuration.LazyLoadingEnabled = false;
var customer = context.Customers.First(x => x.Id == 123);
...
// count the transactions in the last 30 days for this customer
int customerId = customer.Id;
DateTime dateFrom = DateTime.Today.AddDays(-30)
// different variations on the same query
int transactionCount1 = context.Customers.Where(x => x.Id == customerId)
.SelectMany(x => x.Transactions.Where(x => x.TransactionDate >= dateFrom))
.Count();
int transactionCount2 = context.Customers.Where(x => x.Id == customerId)
.SelectMany(x => x.Transactions)
.Where(x => x.TransactionDate >= dateFrom)
.Count();
int transactionCount3 = context.Transactions.Where(x => x.CustomerId == customerId)
.Where(x => x.TransactionDate >= dateFrom)
.Count();
}
很高兴您已经确定要使用IQueryable<T>
我们直接从DbContext
访问它们,而不是从以前检索的实例中访问它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.