表达式列表<Func <T,TProperty >>

Bid*_*dou 11 .net c# lambda entity-framework expression-trees

我正在寻找一种方法来存储Expression<Func<T, TProperty>>用于订单元素的集合,然后针对IQueryable<T>对象执行存储列表(底层提供者是实体框架).

例如,我想做这样的事情(这是伪代码):

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用我的查询方法的存储库:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我的第一个想法是将其Expression<Func<T, TProperty>>转换为字符串(要对其进行排序的属性名称).所以基本上,不是存储类型列表(由于TProperty不是常量,这是不可能的),我存储了一个字符串列表,其中包含要排序的属性.

但这不起作用,因为我无法重建Expression后面(我需要它,因为IQueryable.OrderBy采用Expression<Func<T, TKey>>as参数).

我也尝试动态创建Expression(在Expression.Convert的帮助下),Expression<Func<T, object>>但是我从实体框架中得到一个例外,它说它无法处理Expression.Convert语句.

如果可能,我不想使用像Dynamic Linq Library这样的外部库.

Ani*_*Ani 10

这是少数几种dynamic可能适合使用/反射解决方案的情况之一.

我想你想要这样的东西?(我已经在线条之间阅读并对我认为必要的结构进行了一些更改).

public class OrderClauseList<T>
{
    private readonly List<LambdaExpression> _list = new List<LambdaExpression>();

    public void AddOrderBy<TProperty>(Expression<Func<T, TProperty>> orderBySelector)
    {
        _list.Add(orderBySelector);
    }

    public IEnumerable<LambdaExpression> OrderByClauses
    {
        get { return _list; }
    }
}

public class Repository<T>
{
    private IQueryable<T> _source = ... // Don't know how this works

    public IEnumerable<T> Query(OrderClause<T> clauseList)
    {
        // Needs validation, e.g. null-reference or empty clause-list. 

        var clauses = clauseList.OrderByClauses;

        IOrderedQueryable<T> result = Queryable.OrderBy(_source, 
                                                        (dynamic)clauses.First());

        foreach (var clause in clauses.Skip(1))
        {
            result = Queryable.ThenBy(result, (dynamic)clause);
        }

        return result.ToList();
    }
}
Run Code Online (Sandbox Code Playgroud)

关键的诀窍是让C#dynamic为我们做可怕的重载决策和类型推断.更重要的是,我相信上面的内容,尽管使用dynamic,实际上是类型安全的!