每次访问导航属性时都会读取它们吗?(EF4.1)

Mat*_*tt0 1 entity-framework poco ef-code-first entity-framework-4.1

我正在使用 EF 4.1,带有延迟加载的 POCO。

我运行的一些示例查询:

var discountsCount = product.Discounts.Count();  
var currentDiscountsCount = product.Discounts.Count(d=>d.IsCurrent);  
var expiredDiscountsCount = product.Discounts.Count(d=>d.IsExpired);  
Run Code Online (Sandbox Code Playgroud)

我想知道的是,我的查询是否有意义,或者性能不佳:

我是每次都访问数据库,还是结果来自 DbContext 中的缓存数据?

每次都可以“从头开始”访问导航属性,如上所述,还是应该缓存它们然后对它们执行更多查询,例如:

var discounts = product.Discounts;  
var current = discounts.Count(d=>d.IsCurrent);  
var expired = discounts.Count(d=>d.Expired);  
Run Code Online (Sandbox Code Playgroud)

对于像下面这样的复杂情况,它是拉取整个集合然后对其执行本地操作,还是构造了一个专门的 SQL 查询,这意味着我无法重用结果以避免再次访问数据库:

var chained = discounts.OrderBy(d=>d.CreationDate).Where(d=>d.CreationDate < DateTime.Now).Count();
Run Code Online (Sandbox Code Playgroud)

感谢您的建议!

根据以下评论进行编辑

所以一旦我调用一个导航属性(它是一个集合),它就会加载整个对象图。但是,如果我使用.Count(d=>d...)orSelect(d=>d...)Min(d=>d...)等过滤该集合呢?它是否也加载整个图形,或者仅加载最终数据?

Sla*_*uma 5

product.Discounts(或任何其他导航集合)不是一个,IQueryable而只是一个IEnumerable. 您执行的 LINQ 操作product.Discounts永远不会向数据库发出查询 - 唯一的例外是在延迟加载的情况下product.Discounts将从数据库加载一次到内存中。它将被完全加载 - 无论您执行哪种 LINQ 操作或过滤器。

如果要在不将集合完全加载到内存中的情况下对导航集合执行过滤器或任何查询,则不得访问导航集合,而是通过上下文创建查询,例如在您的示例中:

var chained = context.Entry(product).Collection(p => p.Discounts).Query()
                     .Where(d => d.CreationDate < DateTime.Now).Count();
Run Code Online (Sandbox Code Playgroud)

这不会将Discounts集合加载product到内存中,而是在数据库中执行查询,然后返回单个数字作为结果。这种类型的下一个查询将再次转到数据库。