IQueryable<T> with EntityObject using Generics & Interfaces (Possible?)

天涯浪子 提交于 2019-12-01 12:04:39
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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!