我正在寻找一种方法来存储用于订购元素的 Expression<Func<T, TProperty>>
集合,然后针对 IQueryable<T>
对象执行存储列表(底层提供者是实体框架) .
例如,我想做这样的事情( this is pseudo code ):
public class Program
{
public static void Main(string[] args)
{
OrderClause<User> orderBys = new OrderClause<User>();
orderBys.AddOrderBy(u => u.Firstname);
orderBys.AddOrderBy(u => u.Lastname);
orderBys.AddOrderBy(u => u.Age);
Repository<User> userRepository = new Repository<User>();
IEnumerable<User> result = userRepository.Query(orderBys.OrderByClauses);
}
}
order by子句(要订购的属性):
public class OrderClause<T>
{
public void AddOrderBy<TProperty>(Expression<Func<T, TProperty>> orderBySelector)
{
_list.Add(orderBySelector);
}
public IEnumerable<Expression<Func<T, ???>>> OrderByClauses
{
get { return _list; }
}
}
使用我的查询方法的存储库:
public class Repository<T>
{
public IEnumerable<T> Query(IEnumerable<OrderClause<T>> clauses)
{
foreach (OrderClause<T, ???> clause in clauses)
{
_query = _query.OrderBy(clause);
}
return _query.ToList();
}
}
我的第一个想法是将 Expression<Func<T, TProperty>>
转换为字符串(要对其进行排序的属性名称) . 所以基本上,不是存储类型列表(由于TProperty不是常量,这是不可能的),我存储了一个字符串列表,其中包含要排序的属性 .
但这不起作用,因为我无法重建 Expression
(我需要它,因为IQueryable.OrderBy将 Expression<Func<T, TKey>>
作为参数) .
我还尝试动态创建Expression(在Expression.Convert的帮助下),得到一个 Expression<Func<T, object>>
但是后来我从实体框架中得到一个异常,它说它无法处理Expression.Convert语句 .
如果可能的话,我不想使用像Dynamic Linq Library这样的外部库 .
3 回答
这是少数几种可能适合使用
dynamic
/反射解决方案的情况之一 .我想你想要这样的东西? (我已经在线条之间阅读并对我认为必要的结构进行了一些更改) .
关键的诀窍是让C#
dynamic
为我们做可怕的重载决策和类型推断 . 更重要的是,我相信上面的内容尽管使用了dynamic
,但实际上是类型安全的!一种方法是将所有sort子句“存储”在像
Func<IQueryable<T>, IOrderedQueryable<T>>
这样的函数中(即调用排序方法的函数):这样,您不必处理反射或
dynamic
,所有这些代码都是类型安全且相对容易理解的 .您可以将lambda表达式作为
LambdaExpression
类型的实例存储在集合中 .或者更好的是,存储排序定义,除了表达式之外,每个排序定义都存储排序方向 .
假设您有以下扩展方法
和
ThenBy
类似的方法 . 然后你可以做类似的事情以下是
SortDefinition
和MethodHelper
的定义