调用链中的哪个位置应该包含Include()EF LINQ扩展?

zam*_*6ak 6 linq-to-entities entity-framework

我很好奇在调用链中应该包含在使用Entity Framework时调用的位置.考虑以下方法:

// sample usage from service layer
// _customerRepository.Paginate(1, out totalRecords, 25, "DateJoined DESC, AmountSpent", "DateJoined >= '2009-02-01'", "Invoices, Refunds");
public virtual IQueryable<T> Paginate(int page, out int total, int pageSize, string sort = "Id", string filter = null, string includes = null)
{
    IQueryable<T> query = DatabaseSet;

    total = query.Count(); // get total # of records (required for pagination)...
    var skipTo = GetValidSkipCount(page, total, pageSize);

    if (!String.IsNullOrWhiteSpace(filter))
    {
        query.Where(filter);
    }
    // should includes be before filtering? 
    // should query.Count() be called after query.Include? 
    // does it matter?
    if (!String.IsNullOrWhiteSpace(includes))
    {
        query.IncludeMany(includes); // my own extension that takes comma separated string of entities to include
    }

    return query.OrderBy(sort).Skip(skipTo).Take(pageSize);
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 应该包括总是在调用链中的第一个?
  2. Count()会受到Include的影响吗?如果是这样我想我应该在包括之后做计数
  3. 应该包括在过滤之前还是之后(Where)?
  4. 这真的很重要,因为EF"聪明"足以弄清楚一切吗?

Lad*_*nka 10

应该包括总是在调用链中的第一个?

Include不一定是链中的第一个.Include是非常特殊的运算符,它不是查询的一部分.这就像查询的扩展.它也不是LINQ运算符 - 它是EF运算符定义的ObjectQuery<T>(IQueryable<T>扩展和DbQuery<T>版本都内部到达此实现).该T定义查询的形状和根Include.Include仅在查询的结果形状与Include调用中使用的根匹配时使用.因此,如果您添加Include到调用IQueryable<T>并且您的查询返回IQueryable<T>您Include的应用,但如果您的查询返回IQueryable匿名类型的示例,则更改了查询的形状并且Include未应用.

Count()会受到Include的影响吗?如果是这样我想我应该在包括之后做计数

Include如果您Count在查询上执行,则不使用.Count执行查询并且它不返回数据记录集 - 它改变了形状并且没有任何要包括的内容.

应该包括在过滤之前还是之后(Where)?

没关系.Include创建连接,我希望EF(在构建查询时)和数据库中的查询引擎(在执行查询时)应该在应用连接之前使用过滤.

这真的很重要,因为EF"聪明"足以弄清楚一切吗?

仅当您更改查询的形状时才重要 - 您使用投影或自定义连接.在这种情况下Include,以前的形状将丢失(根本不使用).