LINQ to Entities solo admite la conversión de tipos EDM primitivos o de enumeración con interfaz IEntity

.net c# dbcontext entity-framework expression-trees

Pregunta

Tengo el siguiente método de extensión genérico:

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;
}

Desafortunadamente, Entity Framework no sabe cómo manejar el predicate ya que C # convirtió el predicado a lo siguiente:

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

Entity Framework lanza la siguiente excepción:

No se puede convertir el tipo 'IEntity' para escribir 'SomeEntity'. LINQ to Entities solo admite tipos primitivos o de enumeración EDM de conversión.

¿Cómo podemos hacer que Entity Framework funcione con nuestra interfaz IEntity ?

Respuesta aceptada

Yo era capaz de resolver esto mediante la adición de la class restricción de tipo genérico para el método de extensión. Aunque no estoy seguro de por qué funciona.

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

Respuesta popular

Algunas explicaciones adicionales con respecto a la class "fix".

Esta respuesta muestra dos expresiones diferentes, una con y otra sin la restricción where T: class . Sin la restricción de class tenemos:

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

y con la restricción:

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

Estas dos expresiones son tratadas de manera diferente por el marco de la entidad. Mirando las fuentes de EF 6 , uno puede encontrar que la excepción proviene de aquí, vea ValidateAndAdjustCastTypes() .

Lo que sucede es que EF intenta convertir IEntity en algo que tenga sentido en el mundo del modelo de dominio, sin embargo falla al hacerlo, por lo que se lanza la excepción.

La expresión con la restricción de class no contiene el operador Convert() , la conversión no se ha intentado y todo está bien.

Aún permanece abierta la pregunta, ¿por qué LINQ construye diferentes expresiones? Espero que algún asistente de C # pueda explicar esto.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow