【问题标题】:Creating Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> dynamically?动态创建 Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>?
【发布时间】:2015-02-02 07:26:53
【问题描述】:

我想从SortingItems 列表中动态创建Func&lt;IQueryable&lt;TEntity&gt;, IOrderedQueryable&lt;TEntity&gt;&gt;。 我的意思是我想创建以下表达式:

entity =&gt; entity.OrderBy(c =&gt; c.Id).ThenBy(c =&gt; c.Name).ThenByDescending(c =&gt; c.LastName)

以下是我的代码:

[DataContract]
public class SortingItem
{
    [DataMember]
    public string PropertySelectorString { get; set; }

    [DataMember]
    public SortingDirectionsEnum SortingDirections { get; set; }
}

[DataContract]
public enum SortingDirectionsEnum
{
    [EnumMember]
    Descending = 0,

    [EnumMember]
    Ascending = 1
}

public Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> GetSortingFunc<TEntity>()
{
    _entityType = typeof(TEntity);
    _parameterExpression = Expression.Parameter(_entityType, "entity");
    _iQueryableParameterExpression = Expression.Parameter(typeof(IQueryable<TEntity>), "f");

    MethodInfo orderByMethodInfo = null;
    Expression resultExpression = null;

    foreach (SortingItem sortingItem in SortingItems)
    {
        MemberExpression memberExpression = GetLeftSide(sortingItem.PropertySelectorString, _entityType, _parameterExpression); // I'm dead sure about working this line

        switch (sortingItem.SortingDirections)
        {
            case SortingDirectionsEnum.Descending:
                orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "OrderBy" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type);
                if (resultExpression != null)
                    orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "ThenBy" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type);
                break;

            case SortingDirectionsEnum.Ascending:
                orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "OrderByDescending" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type);
                if (resultExpression != null)
                    orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "ThenByDescending" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type);
                break;
        }

        MethodCallExpression methodCallExpression;
        if (resultExpression != null)
            // Exception
            // An unhandled exception of type 'System.ArgumentException' occurred in System.Core.dll
            // Additional information: Incorrect number of arguments supplied for call to method 'System.Linq.IOrderedQueryable`1[ConsoleApplication1.User] ThenBy[User,Int32](System.Linq.IOrderedQueryable`1[ConsoleApplication1.User], System.Linq.Expressions.Expression`1[System.Func`2[ConsoleApplication1.User,System.Int32]])'
            methodCallExpression = Expression.Call(orderByMethodInfo, _iQueryableParameterExpression, resultExpression, Expression.Lambda(memberExpression, _parameterExpression)); 
        else
            methodCallExpression = Expression.Call(orderByMethodInfo, _iQueryableParameterExpression, Expression.Lambda(memberExpression, _parameterExpression));

        resultExpression = Expression.Lambda(methodCallExpression, _iQueryableParameterExpression);
    }

    Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>> lambdaExpression = Expression.Lambda<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>(resultExpression, _parameterExpression);
    return lambdaExpression.Compile();
}

单独创建{f.OrderBy(entity =&gt; entity.Id)}{f.ThenBy(entity =&gt; entity.Name)} 是可以的,但我在以下行出现异常

methodCallExpression = Expression.Call(orderByMethodInfo, _iQueryableParameterExpression, resultExpression, Expression.Lambda(memberExpression, _parameterExpression)); 

我应该如何使用 Expression.Call{f.OrderBy(entity =&gt; entity.Id)}{f.ThenBy(entity =&gt; entity.Name)} 结合起来,...?

【问题讨论】:

  • 你能解释一下你需要那个吗?可能有一个更简单的解决方案来解决您的“更大的问题”......
  • 我在客户端应用程序中创建了SortingItems 并将其发送给服务。在服务中,我想创建排序 func 以在实体框架中使用

标签: c# entity-framework sorting lambda expression


【解决方案1】:

我建议你不要写这样的代码,因为它很难阅读。过去我不得不维护那些怪物。

如果你真的对解决方案感兴趣,你可以下载 DynamicLINQ,然后你的查询将是:

public string GetSortCriteria(this SortingItem item){
   return string.Format("{0} {1}", item.PropertySelectorString, 
          item.SortingDirections == SortingDirectionsEnum.Descending ? 
             "DESC" : "ASC");
}

// later: 
var mergedSortCriteria= string.Join(",", 
     SortingItems.Select(item => item.GetSortCriteria());

Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> myFunc = 
      source => source.OrderBy("id " + mergedSortCriteria);

【讨论】:

    猜你喜欢
    • 2013-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多