LINQ to Entities only supports casting EDM primitive or enumeration types with IEntity interface

.net c# dbcontext entity-framework expression-trees

Question

I have the following generic extension method:

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

Unfortunately Entity Framework doesn't know how to handle the predicate since C# converted the predicate to the following:

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

Entity Framework throws the following exception:

Unable to cast the type 'IEntity' to type 'SomeEntity'. LINQ to Entities only supports casting EDM primitive or enumeration types.

How can we make Entity Framework work with our IEntity interface?

Accepted Answer

I was able to resolve this by adding the class generic type constraint to the extension method. I'm not sure why it works, though.

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

Popular Answer

Some additional explanations regarding the class "fix".

This answer shows two different expressions, one with and the other without where T: class constraint. Without the class constraint we have:

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

and with the constraint:

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

These two expressions are treated differently by the entity framework. Looking at the EF 6 sources, one can find that the exception comes from here, see ValidateAndAdjustCastTypes().

What happens is, that EF tries to cast IEntity into something that makes sense the domain model world, however it fails in doing so, hence the exception is thrown.

The expression with the class constraint does not contain the Convert() operator, cast is not tried and everything is fine.

It still remain open question, why LINQ builds different expressions? I hope that some C# wizard will be able to explain this.



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why