Some of my entities have IEnabledEntity
interface.
I want to check in repository if entity implements interface then add some predicate. I have the following code:
public class Repository<T> : IRepository<T> where T : class, IEntity, new()
{
public IQueryable<T> Get(Expression<Func<T, bool>> predicate, params string[] includes)
IQueryable<T> query = Context.Set<T>();
foreach (var include in includes)
{
query = query.Include(include);
}
query = query.Where(predicate);
var isEnabledEntity = typeof(IEnabledEntity).IsAssignableFrom(typeof(T));
if (isEnabledEntity)
{
query = query.Where(e => ((IEnabledEntity) e).IsEnabled);
}
return query;
}
public interface IEnabledEntity
{
bool IsEnabled { get; set; }
}
public class Test : IBaseEntity, IEnabledEntity
{
// ...
public bool IsEnabled { get; set; }
}
But, I get exception about casting:
Unable to cast the type 'Domain.Test' to type 'Domain.Interfaces.IEnabledEntity'. LINQ to Entities only supports casting EDM primitive or enumeration types.
How to make it work?
The type parameter in
IQueryable<T>
is covariant, so instead of worrying about casting the entity in your expression, just safe-cast the entire query itself and then useCast<T>()
to get it back to your entity type:Linq-to-Entities only knows models which are classes, that's why an expression can't contain an interface type. However clearly it's possible runtime to access the
IsEnabled
property ifT
implements it, so if you do the check yourself withIsAssignableFrom()
(like you do), it's possible to use theExpressionVisitor
class to bypass the casting:Then you need to create your filter with an extensionmethod which implements the
IgnoreCast
class:Then you can just use that method in your program:
The base method
Visit(Expression e)
will pass each node of the expression to a more specialized Visit method for that kind of node. TheConvert
nodetype is aUnaryExpression
so this method will be overriden in the derived class. If the unaryexpression is of the Convert nodetype and the operand implements the type it will just return the operand, thus removing the casting.