C# IQueryable<;T>;。OrderBy<;T、 对象>;抛出:无法对类型';System.Int16';输入';System.Object';
我们正在使用一个GenericCriteria类,该类用于查询IQueryable,而无需直接访问它。基本上,查询构建在“业务”层,并传递到“数据访问”层。为了防止重复,它需要尽可能通用 下面是GenericCriteria类的简化版本:C# IQueryable<;T>;。OrderBy<;T、 对象>;抛出:无法对类型';System.Int16';输入';System.Object';,c#,linq,entity-framework,generics,C#,Linq,Entity Framework,Generics,我们正在使用一个GenericCriteria类,该类用于查询IQueryable,而无需直接访问它。基本上,查询构建在“业务”层,并传递到“数据访问”层。为了防止重复,它需要尽可能通用 下面是GenericCriteria类的简化版本: public class GenericCriteria<T> { public Expression<Func<T, bool>> Where { get; set; } public Expression
public class GenericCriteria<T>
{
public Expression<Func<T, bool>> Where { get; set; }
public Expression<Func<T, object>> OrderBy { get; set; }
}
所以我现在想弄清楚的是如何让GenericCriteria类接受某种类型的泛型OrderBy构造,这样EF就可以完成它的任务了
我应该找什么
更新:
如果不清楚,我宁愿避免:
public class GenericCriteria<T, TKey>
{
public Expression<Func<T, bool>> Where { get; set; }
public Expression<Func<T, TKey>> OrderBy { get; set; }
}
公共类通用标准
{
公共表达式,其中{get;set;}
公共表达式OrderBy{get;set;}
}
因为类的用户可能并不总是想要订购,所以需要一个类型似乎有点脏。我将重写以下条件
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>>>();
}
}
公共类通用标准
{
公开名单
列表{get;private set;}
公共通用标准(){
列表=新列表();
}
}
决心
public static IQueryable<T> ResolveCriteria<T>(this IQueryable<T>
query, GenericCriteria<T> criteria)
{
foreach(var exp in criteria.List){
query = exp(query);
}
return query;
}
公共静态IQueryable ResolveCriteria(此IQueryable
查询,一般条件(标准)
{
foreach(criteria.List中的var exp){
query=exp(查询);
}
返回查询;
}
用法
var-criteria=新的GenericCriteria();
添加(q=>q.Where(c=>c.Age>20));
criteria.List.Add(q=>q.OrderBy(c=>c.Age));
var persons=Data.Instance.GetPersons(标准);
由于您不希望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;
}
公共静态IQueryable ResolveCriteria(此IQueryable查询,GenericCriteria)
{
query=query.Where(criteria.Where);
var t=criteria.OrderBy;
var b=t.体;
if(b.NodeType==ExpressionType.Convert&&
((一元表达式)b).Type==typeof(对象)){
//处理简单类型,如short、int、long等。
var bb=((一元表达式)b).操作数;
var tt=表达式λ(bb,t.参数);
if(bb.Type==typeof(short))
query=query.OrderBy((表达式)tt);
else if(bb.Type==typeof(int))
query=query.OrderBy((表达式)tt);
否则如果(…)
...
}否则
//处理非简单类型,例如字符串。
query=query.OrderBy(t);
返回查询;
}
对于每个简单类型,您都需要一个“else-if”;幸运的是,数量不多。有关简单类型的列表,请参阅。为什么您的orderBy接口属性不是泛型的?您是否有一个初始化/填充条件的示例?是否可以使用
dynamic
关键字?通过创建表达式,可以重写orderBy表达式以将强制类型转换为正确的类型访客,但这不是小事。我从来都不理解在堆栈中隐藏iQueryTables的驱动力,你只需要编写大量代码就可以得到一个残缺版本的Linqt。在.net中有一个名为ExpressionVisitor的基类,你可以继承它,它可以解析和重写表达式。您可以让它按表达式的顺序进行迭代,获得最终属性(可以按嵌套属性进行排序),确定其类型,然后将强制转换放入它生成的新表达式中,然后在OrderBy中使用它。这里有一个介绍,谢谢。我一直在玩弄这个想法(使用Func作为参数)。这种方法的缺点是,我需要引用实体框架,以便在System.Data.Entity中使用扩展方法“Include”。这不是最糟糕的问题,但更愿意避免。
public class GenericCriteria<T, TKey>
{
public Expression<Func<T, bool>> Where { get; set; }
public Expression<Func<T, TKey>> OrderBy { get; set; }
}
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);
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;
}