EF SQL changed when passing predicate as Parameter to Where Clause

﹥>﹥吖頭↗ 提交于 2020-01-13 09:21:39

问题


EF is generating different SQL for the for two similar statements listed below

var test = dbcontext.Persons.GetAll()
                            .Where(c => c.PersonID == 2)
                            .Select(c => c.PersonName)
                            .FirstOrDefault();`

Generated SQL:

SELECT 
    [Limit1].[PersonName ] AS [PersonName ]
FROM 
    (SELECT TOP (1)
         [Extent1].[PersonName ] AS [PersonName ]
     FROM 
         [dbo].[ApplicationRequest] AS [Extent1]
     WHERE 
         [Extent1].[PersonID ] = @p__linq__0) AS [Limit1]',N'@p__linq__0 uniqueidentifier',@p__linq__0= "2"

I am using the above statements at multiple places with different Where condition; to consolidate logic in one place I am passing the condition as a parameter

Public Void PassPredicate(Func<ApplicationRequest, bool> ReqFunc)
{
    var test = dbcontext.Persons.GetAll()
                                .Where(ReqFunc)
                                .Select(c => c.PersonName)
                                .FirstOrDefault();
}

I am calling the function as

PassPredicate(c => c.PersonID == 2);

Generated SQL:

SELECT 
    [Extent1].[PersonID] AS [PersonID], 
    [Extent1].[PersonName ] AS [PersonName ], 
    [Extent1].[DOB] AS [Dob], 
    [Extent1].[Height] AS [Height],
    [Extent1].[BirthCity] AS [BirthCity], 
    [Extent1].[Country] AS [Country],
FROM 
    [dbo].[Person] AS [Extent1]

If you look at the second SQL, it is quite alarming: it is pulling all info (columns and rows). It doesn't have where clause and selecting all columns.

The where condition is being applied after the results were returned from DB.

The only difference in the second statement is I am passing condition as parameter instead of having condition inside where clause.

Can anyone explain why the difference?


回答1:


Since ReqFunc type is Func<ApplicationRequest, bool> you're using Enumerable extensions, so your code (Where, Select, FirstOrDefault) will be executed in-memory.

To fix this, just change ReqFunc to Expression<Func<ApplicationRequest, bool>> to use Queryable extensions:

Public Void PassPredicate(Expression<Func<ApplicationRequest, bool>> ReqFunc)
{
    var test = dbcontext.Persons.GetAll().Where(ReqFunc).Select(c => c.PersonName).FirstOrDefault();
}



回答2:


The IQueryable Where takes an Expression<Func<TSource, bool>>, NOT a Func<TSource, bool>, so a different overload of Where is being called, causing the query to execute and the result to be returned as an IEnumerable instead of an IQueryable.

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

Pass your Func as an Expression and you should get the desired behavior.



来源:https://stackoverflow.com/questions/37348488/ef-sql-changed-when-passing-predicate-as-parameter-to-where-clause

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!