【发布时间】:2015-07-06 08:26:19
【问题描述】:
我们正在使用一个 GenericCriteria 类,该类用于查询 IQueryable 而无需直接访问它。基本上,查询构建在“业务”层并传递到“数据访问”层。为了防止重复,它需要尽可能通用。
这是 GenericCriteria 类的简化版本:
public class GenericCriteria<T>
{
public Expression<Func<T, bool>> Where { get; set; }
public Expression<Func<T, object>> OrderBy { get; set; }
}
解析条件是通过 IQueryable 上的扩展方法完成的:
public static IQueryable<T> ResolveCriteria<T>(this IQueryable<T> query, GenericCriteria<T> criteria)
{
query = query.Where(criteria.Where);
query = query.OrderBy(criteria.OrderBy);
return query;
}
这是它在数据层中的解析方式:
public ICollection<Person> GetPersons(GenericCriteria<Person> criteria)
{
using (var context = new EFContext())
{
return context.Persons
.AsQueryable()
.ResolveCriteria(criteria)
.ToList();
}
}
其用法示例:
var criteria = new GenericCriteria<Person>();
criteria.Where = c => c.Age > 20;
criteria.OrderBy = c => c.Age;
var persons = Data.Instance.GetPersons(criteria);
问题是Entity Framework无法处理OrderBy表达式的object类型,抛出异常:
Unable to cast the type 'System.Int16' to type 'System.Object'
所以我现在想弄清楚的是如何让 GenericCriteria 类接受某种通用 OrderBy 构造,以便 EF 能够完成它的工作。
我应该寻找什么?
更新:
如果不清楚,我宁愿避免:
public class GenericCriteria<T, TKey>
{
public Expression<Func<T, bool>> Where { get; set; }
public Expression<Func<T, TKey>> OrderBy { get; set; }
}
因为该类的用户可能并不总是想要订购,所以要求一个类型似乎有点脏。
【问题讨论】:
-
为什么你的 orderBy 接口属性不是通用的?
-
你有没有初始化/填充条件的例子?
-
可以使用
dynamic关键字吗? -
可以通过创建表达式访问者来重写 OrderBy 表达式以将强制转换为正确的类型,但这并不简单。我从来没有理解将 IQueryables 隐藏在堆栈中的驱动力,你最终只是编写了大量代码来拥有一个残缺的 Linq 版本
-
.net 中有一个名为 ExpressionVisitor 的基类,您可以从它继承来解析和重写表达式。您可以让它按表达式进行排序,获取最终属性(您可以按嵌套属性排序),确定其类型,然后将强制转换放入它生成的新表达式中,然后在 OrderBy 中使用它。这里有一个介绍pelebyte.net/blog/2011/05/13/…
标签: c# linq entity-framework generics