c# - 表达式列表 <Func<T, TProperty>>

标签 c# .net entity-framework lambda expression-trees

我正在寻找一种方法来存储 Expression<Func<T, TProperty>> 的集合用于对元素进行排序,然后针对 IQueryable<T> 执行存储的列表对象(底层提供者是 Entity Framework )。

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

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.Convert 的帮助下),以获得 Expression<Func<T, object>>但后来我从 Entity Framework 中得到一个异常,说它无法处理 Expression.Convert 语句。

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

最佳答案

这是动态/反射解决方案可能适用的少数情况之一。

我想你想要这样的东西? (我已经阅读了字里行间的内容,并在我认为必要的地方对您的结构进行了一些更改)。

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();
    }
}

关键技巧是让 C# dynamic 为我们执行可怕的重载解析和类型推断。更重要的是,我相信上面的内容,尽管使用了 dynamic,实际上是类型安全的!

关于c# - 表达式列表 <Func<T, TProperty>>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16678057/

相关文章:

c# - 使用正则表达式和下推自动机匹配嵌套括号组

c# - 如何控制 Datagridview 中的 SendKeys.Send {"tab"} 属性?

.net - .NET 4 中的新 HandleProcessCorruptedStateExceptions 属性

c# - 在 Startup.cs 中使 ConfigureServices 方法异步

c# - 使用单声道从 C++ 传递 C# 枚举

c# - 访问 select 中的透明标识符会引发它不是从范围引用的

c# - 如何将显示属性设置为 E.F. 生成的枚举?

c# - 是否有示例说明为什么应在 NHibernate 中覆盖 Equals/GetHashCode?

C# Multiline 多双引号字符串

entity-framework - 必须映射。它没有默认值且不可为空