传递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...
}
}
答案 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扩展方法,这样您就可以执行正确的查询并返回结果。