2016-05-20 11 views
7

EF jest generowanie różnych SQL dla dwóch podobnych oświadczeń wymienionych poniżejEF SQL zmienione podczas przechodzenia predykatu jako parametr, gdzie klauzula

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" 

używam powyższe oświadczenia w wielu miejscach o innym stanie niż Where; skonsolidować logiki w jednym miejscu ja przechodząc stan jako parametr

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

Wołam funkcję jako

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] 

Jeśli spojrzeć na sekundę SQL, to dość alarmujące: pobiera wszystkie informacje (kolumny i wiersze). Nie ma tam klauzuli where i wyboru wszystkich kolumn.

Warunek miejsca jest stosowany po zwróceniu wyników z DB.

Jedyną różnicą w drugiej instrukcji jest to, że przekazuję warunek jako parametr zamiast warunku wewnątrz klauzuli where.

Czy ktoś może wyjaśnić, dlaczego różnica?

+0

'var test = dbcontext.Persons.GetAll(). Gdzie (c => c.PersonID == 2). Wybierz (c => c.PersonName) .FirstOrDefault();' dlaczego nie używasz prostego wyrażenia jak 'var test = dbcontext.Persons.FirstOrDefault (c => c.PersonID == 2). Wybierz (c => c.PersonName);' –

+0

Jestem trochę związany z wykorzystaniem innych niż GetALL.Aktualnie nie używamy Dokładna składnia .. Używamy czegoś w rodzaju PersonsRepository.GetAll() ... Repozytorium ujawnia tylko ograniczone funkcjonalności –

+0

oky, ale myślę, że używa dodatkowych zasobów. –

Odpowiedz

6

Od ReqFunc typ jest Func<ApplicationRequest, bool> używasz Enumerable rozszerzeń, więc kod (Where, Select, FirstOrDefault) będą realizowane w pamięci.

Aby rozwiązać ten problem, wystarczy zmienić ReqFunc do Expression<Func<ApplicationRequest, bool>> używać Queryable rozszerzenia:

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

Pracowałem ... To dlatego musisz dokładnie zrozumieć tę koncepcję zanim zaczniesz kodować ... zamiast uzyskiwać natychmiastowe rozwiązania poprzez przepełnienie stosu .. Nienawidzę tego robić ... ale wciąż to robię;) –

0

IQueryable Gdzie trwa Expression<Func<TSource, bool>>, a nie Func<TSource, bool>, więc inny przeciążenie Gdzie jest nazywany, powodując zapytanie do Wykonaj, a wynik do zwrócenia jako IEnumerable zamiast IQueryable.

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

Przekaż Func jako wyraz i powinieneś uzyskać pożądane zachowanie.