2015-07-14 17 views
9

Ho due metodi di estensione come questoLINQ to Entities non supporta il metodo di estensione?

public static IQueryable<T> CurrentVersion(this IQueryable<T> queryable, DateTime date) 
    { 
     return queryable.Where(p => p.CreationDate>date); 
    } 

    public static IEnumerable<T> CurrentVersion(this IEnumerable<T> queryable, DateTime date) 
    { 
     return queryable.Where(p => p.CreationDate>date); 
    } 

Il mio modello è

public class Group { 
    .. 
    ICollection<GroupMembers> GroupMembers { get; set; } 
} 

Quando uso dal metodo di estensione in questa query è tutto ok

var q = Db.Groups.CurrentVersion(); 
var result = q.ToList(); 

Ma quando lo uso nella query che scorre ottengo un errore

var q = Db.Groups.SelectMany(p => p.GroupMembers.AsQueryable().CurrentVersion(date)); 

OR 

var q = Db.Groups.SelectMany(p => p.GroupMembers.AsEnumerable().CurrentVersion(date)); 

var result = q.ToList(); // Here I get error 

Errore:

LINQ to Entities does not recognize the method 'System.Linq.IQueryable 1[..](System.Linq.IQueryable 1[..., System.DateTime)' method, and this method cannot be translated into a store expression.

Ora ho due domande:

  1. I Googled questo errore e ha trovato lo stesso come la mia domanda a StackOverflow molti problemi. Tutte le risposte erano "Linq to Entities non può convertire questo metodo di estensione in una query SQL". Ora sarei grato se qualcuno mi aiutasse a sapere, perché la mia prima domanda non genera errori?

  2. Come posso modificare il metodo di estensione che può essere riconosciuto da Linq-to-Entities?

risposta

6

La query di Linq deve essere convertita in sql. Quando hai il tuo estensione CurrentVersion chiamato in linea come questo:

Db.Groups.CurrentVersion(); 

poi EF solo richiama il metodo CurrentVersion, ottiene risultante oggetto IQueryable e trasforma in interrogare. D'altra parte in caso di tale query:

var q = Db.Groups.SelectMany(p => p.GroupMembers.AsQueryable().CurrentVersion(date)); 

L'espressione interna in SelectMany non può mai essere invocata nel codice! È pensato per essere tradotto in sql. Quindi viene trattato come oggetto Expression e quindi viene analizzato, ma nel tuo caso contiene Invoke Expression mentre stai invocando il metodo ma questo non può essere tradotto in sql da ovvi motivi. Quindi dal parameer lambda SelectMany non puoi invocare alcun metodo, devi fornire un'espressione corretta. La cosa più preziosa fornita dal metodo CurrentVersion è l'espressione filtrante. Cambia la tua metodo come questo:

public static Expression<T, bool> CurrentVersion(DateTime date) 
{ 
    return p => p.CreationDate > date; 
} 

un uso così:

var q = Db.Groups.Where(ExpressionsHelper.CurrentVersion(date)); 
... 
Expression<T, bool> filterExpression = ExpressionsHelper.CurrentVersion(date); 
Db.Groups.SelectMany(p => p.GroupMembers.AsQueryable().Where(filterExpression)); 

Se whish si può stil avere la logica di condivisione di filtraggio metodo di estensione con il nuovo metodo:

public static IQueryable<T> CurrentVersion(this IQueryable<T> queryable, DateTime date) 
{ 
    return queryable.Where(ExpressionsHelper.CurrentVersion(date)); 
} 
+0

Penso che la tua estensione non sia diversa con il mio metodo di estensione perché queryable.Where (ExpressionsHelper.CurrentVersion (date)) è uguale a queryable.Where (p => p.CreationDate> date); –

+0

Indeed queryable.Where (ExpressionsHelper.CurrentVersion (date)) dovrebbe funzionare come queryable.Where (p => p.CreationDate> date); ma questo era l'obiettivo, giusto? Ho cambiato il tuo metodo in modo che la tua logica di filtraggio possa essere riutilizzata, come volevi. Quindi la differenza dovrebbe essere che il metodo proposto da me sta funzionando e EF può analizzarlo per interrogarlo. – mr100

+0

Ma la mia versione del metodo di estensione CurrentVersion non può essere applicata alla query nidificata! Puoi usarlo solo con query semplici come Db.Groups.Versione attuale(); Per quelli complessi è necessario utilizzare Db.Groups.SelectMany (p => p.GroupMembers.AsQueryable(). Where (ExpressionsHelper.CurrentVersion (date))); Il metodo di estensione è presentato solo come esempio - se vuoi averlo, puoi averlo senza duplicazione del codice. – mr100