LINQ to Entities supporta solo il casting di tipi primitivi o di enumerazione EDM con l'interfaccia IEntity

.net c# dbcontext entity-framework expression-trees

Domanda

Ho il seguente metodo di estensione generico:

public static T GetById<T>(this IQueryable<T> collection, Guid id) 
    where T : IEntity
{
    Expression<Func<T, bool>> predicate = e => e.Id == id;

    T entity;

    // Allow reporting more descriptive error messages.
    try
    {
        entity = collection.SingleOrDefault(predicate);
    }
    catch (Exception ex)
    {
        throw new InvalidOperationException(string.Format(
            "There was an error retrieving an {0} with id {1}. {2}",
            typeof(T).Name, id, ex.Message), ex);
    }

    if (entity == null)
    {
        throw new KeyNotFoundException(string.Format(
            "{0} with id {1} was not found.",
            typeof(T).Name, id));
    }

    return entity;
}

Purtroppo Entity Framework non sa come gestire il predicate poiché C # ha convertito il predicato nel modo seguente:

e => ((IEntity)e).Id == id

Entity Framework lancia la seguente eccezione:

Impossibile eseguire il cast del tipo "IEntity" per digitare "SomeEntity". LINQ to Entities supporta solo il casting di tipi primitivi o di enumerazione EDM.

Come possiamo far funzionare Entity Framework con la nostra interfaccia IEntity ?

Risposta accettata

Sono stato in grado di risolvere questo problema aggiungendo il vincolo di tipo generico di class al metodo di estensione. Non sono sicuro del perché funzioni, però.

public static T GetById<T>(this IQueryable<T> collection, Guid id)
    where T : class, IEntity
{
    //...
}

Risposta popolare

Alcune spiegazioni aggiuntive riguardanti la class "fix".

Questa risposta mostra due diverse espressioni, una con e l'altra senza where T: class vincolo di where T: class . Senza il vincolo di class abbiamo:

e => e.Id == id // becomes: Convert(e).Id == id

e con il vincolo:

e => e.Id == id // becomes: e.Id == id

Queste due espressioni sono trattate in modo diverso dalla struttura dell'entità. Guardando le fonti EF 6 , si può scoprire che l'eccezione arriva da qui, vedi ValidateAndAdjustCastTypes() .

Quello che succede è che EF cerca di IEntity in qualcosa che abbia senso nel mondo del modello di dominio, tuttavia fallisce nel farlo, quindi viene lanciata l'eccezione.

L'espressione con il vincolo di class non contiene l'operatore Convert() , il cast non viene provato e tutto va bene.

Rimane ancora una domanda aperta, perché LINQ costruisce espressioni diverse? Spero che qualche wizard C # sarà in grado di spiegarlo.



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché