我有两个具有共同属性的实体。我需要使用通用属性在查询中的某些位置应用。所以我决定这样做:
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" };
}
}
问题是使用这种方式,并且在套用.ToList()之后,我收到:
NotSupportedException。 LINQ to Entities仅支持强制转换EDM基本类型或枚举类型。
我有一种解决方法,还是需要使用ObjectQuery的Where(string)?
谢谢
最佳答案
问题是,您对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);
关于entity-framework - Entity Framework 常见之处,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24577957/