3

I have two entities with common properties. I need to apply some where in my query using the common properties. So I decide to do this:

public interface IContract
{
    string Name{get;set;}
}

public class Entity1 : IContract
{
    public string Name{get;set;}
}

public class Entity2 : IContract
{
    public string Name{get;set;}
}

public class Repository
{
    public IQueryable<T> Filter<T>(IQueryable<T> query, Request request) where T : IContract
    {
        return query.Where(x => x.Name== request.Name);
    }
    public IQueryable<Entity1> GetEntitity1()
    {
        return Filter(entities.Entity1, new Request { Name = "X" };
    }

    public IQueryable<Entity2> GetEntitity2()
    {
        return Filter(entities.Entity2, new Request { Name = "X" };
    }
}

The problem is using this way and after apply .ToList() I receive: NotSupportedException. LINQ to Entities only supports casting EDM primitive or enumeration types.

I there a way to fix it or I need to use the Where(string) of ObjectQuery?

Thanks

4

1 回答 1

0

问题是,您对 T 的类型约束是一个接口。filter 方法的结果基本上是这样的查询。

entities.Entity1.Where(p => ((IContract)p).Name == request.Name);

此 ((IContract)p) 强制转换无法转换为 sql 语句。由于这种转换在您的情况下或多或少无用,因此可以简单地从查询表达式中删除它。最好的方法是使用 ExpressionVisitor。

public IQueryable<T> Filter<T>(IQueryable<T> query, Request request) where T : IContract
{
    var result =  query.Where(x => x.Name == request.Name);
    result = RemoveContract<T, IContract>(result);
    return result;
}

public IQueryable<T> RemoveContract<T, TContract>(IQueryable<T> query) where T : TContract
{
    var exp = query.Expression;
    exp = new RemoveConvertExpressionVisitor<TContract>().Visit(exp);
    return query.Provider.CreateQuery<T>(exp);
}

private class RemoveConvertExpressionVisitor<TContract> : ExpressionVisitor{
    public override Expression Visit(Expression node)
    {
        var unary = node as UnaryExpression;
        if (unary != null && unary.Type == typeof(TContract)) {
            return unary.Operand;
        }
        return base.Visit(node);
    }
}

调用 RemoveContract 方法后,查询如下所示。

entities.Entity1.Where(p => p.Name == request.Name);
于 2014-07-04T17:07:14.533 回答