I have a search repository for EntityFramework 4.0 using LinqKit with the following search function:
public IQueryable Search(Expression<
The natural response to this is to actually define the SubsetByUser() method to use a constraint with a GUID property: ... But this doesn't work. I'm using LinqKit and the Expandable() method results in: System.NotSupportedException: Unable to cast the type 'Oasis.DataModel.Arc' to type 'Oasis.DataModel.Interfaces.IHaveMetadata'. LINQ to Entities only supports casting Entity Data Model primitive types
You're very close with that. You can make this work if you use an ExpressionVisitor
that removes all unnecessary casts (casts to a base type or an implemented interface) that are automatically generated.
public IQueryable<T> SubsetByUser<T>(IQueryable<T> set, User user)
where T : IHaveMetadata
{
Expression<Func<T, Guid>> GetGUID = arc => arc.GUID;
GetGUID = (Expression<Func<T, Guid>>)RemoveUnnecessaryConversions.Instance.Visit(GetGUID);
return set.Join(_searcher.Search<Metadatum>((o) => o.UserGUID == user.GUID),
GetGUID,
meta => meta.ElementGUID,
(arc, meta) => arc);
}
public class RemoveUnnecessaryConversions : ExpressionVisitor
{
public static readonly RemoveUnnecessaryConversions Instance = new RemoveUnnecessaryConversions();
protected RemoveUnnecessaryConversions() { }
protected override Expression VisitUnary(UnaryExpression node)
{
if (node.NodeType == ExpressionType.Convert
&& node.Type.IsAssignableFrom(node.Operand.Type))
{
return base.Visit(node.Operand);
}
return base.VisitUnary(node);
}
}
Alternatively, create the expression tree manually using the Expression.*
functions, so that you can avoid including the cast in the first place.