我们正在使用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; }
}
因为类的用户可能并不总是想订购,所以要求类型看起来有点脏。
答案 0 :(得分:1)
我将重写Criteria,如下所示,
public class GenericCriteria<T>
{
public List<Func<IQueryable<T>,IQueryable<T>>>
List { get; private set;}
public GenericCriteria<T>(){
List = new List<Func<IQueryable<T>,IQueryable<T>>>();
}
}
解决
public static IQueryable<T> ResolveCriteria<T>(this IQueryable<T>
query, GenericCriteria<T> criteria)
{
foreach(var exp in criteria.List){
query = exp(query);
}
return query;
}
用法
var criteria = new GenericCriteria<Person>();
criteria.List.Add( q => q.Where( c => c.Age > 20) );
criteria.List.Add( q => q.OrderBy( c => c.Age ));
var persons = Data.Instance.GetPersons(criteria);
答案 1 :(得分:1)
由于您不希望GenericCriteria
有两个类型参数,而OrderBy
坚持使用两个类型参数,可能最好的方法是在ResolveCriteria
中执行一些脏工作,如下:
public static IQueryable<T> ResolveCriteria<T>(this IQueryable<T> query, GenericCriteria<T> criteria)
{
query = query.Where(criteria.Where);
var t = criteria.OrderBy;
var b = t.Body;
if (b.NodeType == ExpressionType.Convert &&
((UnaryExpression)b).Type == typeof(Object)) {
// Handle simple types, such as short, int, long, etc.
var bb = ((UnaryExpression)b).Operand;
var tt = Expression.Lambda(bb, t.Parameters);
if (bb.Type == typeof(short))
query = query.OrderBy((Expression<Func<T, short>>)tt);
else if (bb.Type == typeof(int))
query = query.OrderBy((Expression<Func<T, int>>)tt);
else if (...)
...
} else
// Handle non-simple types, such as string.
query = query.OrderBy(t);
return query;
}
每种简单类型都需要“else if”;幸运的是,并不多。有关简单类型的列表,请参阅C# Simple Types。