如何维护LINQ延迟执行?

mck*_*mey 8 c# linq iqueryable deferred-execution

假设我有一个IQueryable<T>表达式,我想封装它的定义,存储它并重用它,或者稍后将它嵌入到更大的查询中.例如:

IQueryable<Foo> myQuery =
    from foo in blah.Foos
    where foo.Bar == bar
    select foo;
Run Code Online (Sandbox Code Playgroud)

现在我相信我可以保持myQuery对象并像我描述的那样使用它.但有些事情我不确定:

  1. 如何最好地参数化?最初我在一个方法中定义了这个,然后IQueryable<T>作为方法的结果返回.这样我就可以定义blahbar作为方法参数,我猜它IQueryable<T>每次都会创建一个新的.这是封装逻辑的最佳方法IQueryable<T>吗?还有其他方法吗?

  2. 如果我的查询解析为标量而不是IQueryable 例如,如果我希望此查询完全如所示,但附加.Any()只是让我知道是否有任何匹配的结果?如果我添加,(...).Any()则结果bool立即执行,对吧?有没有使用这些方式Queryable运营(Any,SindleOrDefault,等),但不立即执行?LINQ-to-SQL如何处理这个问题?

编辑:第2部分更多的是试图了解IQueryable<T>.Where(Expression<Func<T, bool>>)vs. 之间的限制差异IQueryable<T>.Any(Expression<Func<T, bool>>).在创建要延迟执行的大型查询时,似乎后者并不灵活.的Where()可以追加,然后在其它构建体可以稍后所附,然后最终执行.由于Any()返回标量值,因此它可以在构建其余查询之前立即执行.

Jos*_*eph 5

  1. 当你使用DataContext时,你必须非常小心地传递IQueryables,因为一旦上下文被处理掉,你就不能再在那个IQueryable上执行了.如果您没有使用上下文,那么您可能没问题,但要注意这一点.

  2. .Any()和.FirstOrDefault()不会延期.当你调用它们时,它们导致执行.但是,这可能不符合您的想法.例如,在LINQ to SQL中,如果在IQueryable上执行.Any(),它基本上充当IF EXISTS(SQL HERE).

如果您愿意,可以像这样链接IQueryable:

var firstQuery = from f in context.Foos
                    where f.Bar == bar
                    select f;

var secondQuery = from f in firstQuery
                    where f.Bar == anotherBar
                    orderby f.SomeDate
                    select f;

if (secondQuery.Any())  //immediately executes IF EXISTS( second query in SQL )
{
    //causes execution on second query 
    //and allows you to enumerate through the results
    foreach (var foo in secondQuery)  
    {
        //do something
    }

    //or

    //immediately executes second query in SQL with a TOP 1 
    //or something like that
    var foo = secondQuery.FirstOrDefault(); 
}
Run Code Online (Sandbox Code Playgroud)