3

在我的 Entity Framework Code First 项目中,我有一个包含路由的存储库对象

public class EFRepository
{
    ...
    public IQueryable<Route> Routes
    {
        get { return context.Routes; }
    }
   ...
}

如果我跑

var routes = this.repository.Routes
                  .Where(r => r.DeployedService.IsActive.HasValue 
                   && r.DeployedService.IsActive.Value);

路线对象的类型IQueryable<Route>

但是,如果我运行

Func<Route, bool> routeIsActive = r => r.DeployedService.IsActive.HasValue 
                                      && r.DeployedService.IsActive.Value;
var routes = this.repository.Routes.Where(routeIsActive);

在这种情况下,路由对象的类型是IEnumerable<Route>

我原以为他们会被评估相同,但显然我错了。这两个语句有什么区别,为什么它们返回不同的类型。

4

3 回答 3

5

该方法.Where(Expression<Func<Route,bool>>)由 定义IQueryable<Route>.Where(Func<Route,bool>)另一方面,该方法是由IEnumerable<Route>而不是由定义的IQueryable<Route>。因此,每个都为流畅的 LINQ 方法链接返回自己的类型。

定义的附加方法IQueryable允许将表达式树下推到 LINQ 提供程序,例如 LINQ-to-entities,以便在可能的情况下在提供程序级别进行延迟延迟评估。

于 2012-07-18T10:13:55.090 回答
4

因为传递Func<Route,bool>会使它成为 Linq-to-objects(Func是 .NET 委托,它将在 .NET 代码中执行)。它告诉 EF:加载所有路由,我将在 .NET 代码中进行过滤。

您需要传递一个表达式 ( Expression<Func<Route,bool>>),该表达式将在内部转换为 SQL 以使用 Linq-to-entities。它告诉 EF:这是我要转换为 SQL 并在数据库服务器上执行的过滤器,我只想接收过滤后的结果集。

于 2012-07-18T10:11:17.920 回答
2

IQuerable<T> inherits from IEnumerable<T>. This means that Where is overloaded:

One overload takes an expression and returns an IQuerable<T>.

public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)

The other overload takes a function and returns an IEnumerable<T>.

public static IQueryable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)

If you pass in a lambda, both overloads are applicable, and overload resolution prefers the first one. If you pass in a Func<T,bool>, then only the second overload is applicable.

If you change the type of your variable to Expression<Func<Route, bool>>, then you'll get an IQueryable<Route> back.

于 2012-07-18T10:14:31.733 回答