Func Delegates导致LINQ-to-Entities拉回整个表

时间:2016-10-06 20:09:26

标签: c# entity-framework linq lambda linq-to-entities

传递Func<>作为Where / Count过滤器导致LINQ拉回整个表。这是一个简单的例子。

pdx.Database.Log = strWriter1.Write;
totalCount = pdx.Principals.Count(x => x.PrincipalNumber.ToLower().Contains("42"));

查看我看到的日志

SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT  COUNT(1) AS [A1]
   FROM [Dealer].[Principal] AS [Extent1] 
WHERE LOWER([Extent1].[PrincipalNumber]) LIKE N'%42%'
)  AS [GroupBy1]

没有拉回整张桌子。很简单。现在让我们将该lambda分配给Func<>

pdx.Database.Log = strWriter2.Write;
Func<Principal, bool> filter = (x => x.PrincipalNumber.ToLower().Contains("42"));
totalCount = pdx.Principals.Count(filter);

日志显示它正在拉下整个表格。

SELECT 
[Extent1].[PrincipalNumber] AS [PrincipalNumber], 
[Extent1].[Id] AS [Id], 
[Extent1].[CompanyName] AS [CompanyName], 
...
[Extent1].[DistrictSalesManagerId] AS [DistrictSalesManagerId]
FROM [Dealer].[Principal] AS [Extent1]

这对性能来说非常糟糕。我有执行LINQ查询的函数。我想将lambda过滤器传递给这些函数,所以我可以过滤各种各样的东西,但显然我不能将lambdas作为Func&lt;&gt; s传递,因为它会破坏性能。我有什么选择?

我想做什么......

public IEnumerable<DealerInfo> GetMyPage(Func<Principal, bool> filter, int pageNumber, int pageSize, out int totalCount)
{
    List<DealerInfo> dealers;

    using (MyContext pdx = new MyContext())
    {
        totalCount = pdx.Principals.Count(filter);
        // More LINQ stuff here, but UGH the performance...
    }
}

1 个答案:

答案 0 :(得分:3)

您实际上需要传递Expression<Func<TSrource,T>>,Linq到实体无法将Func<T>转换为sql,将签名更改为:

public IEnumerable<DealerInfo> GetMyPage(Expression<Func<Principal, bool>> filter, int pageNumber, int pageSize, out int totalCount)
{
    List<DealerInfo> dealers;

    using (MyContext pdx = new MyContext())
    {
        totalCount = pdx.Principals.Count(filter);
        // More LINQ stuff here, but UGH the performance...
    }
}

当您在Func<T,TResult>>方法中传递Count作为参数时,它将调用内存集合中的IEnumerable<T>的Count方法扩展方法,这样就会导致整个表数据首先加载到内存中,然后计数委托在加载所有数据时执行,并在内存中执行提供的委托调用,同时传递Expression<Func<T>>作为参数将使语句转换为正确的sql(如果可能)然后将调用IQueryable<T>的Count扩展方法,这样您就可以执行正确的查询并返回结果。