表达式 OrderBy Then 通过返回 (Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>)

Expression OrderBy Then By returning (Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>)

我有一个存储库 class 如下。我的问题出在 GetSelected 方法

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{

    protected readonly DbContext Db;
    protected readonly DbSet<TEntity> DbSet;
    
    public Repository(DbContext context)
    {
        Db = context;
        DbSet = Db.Set<TEntity>();
    }

    //CRUD Operations

    public IEnumerable<TEntity> GetSelected(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, params Expression<Func<TEntity, object>>[] includeProperties)
    {
        IQueryable<TEntity> query = DbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties)
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }
}

我正在尝试通过提供如下参数来对部门进行排序。

[Route("api/[controller]")]
[ApiController]
public class DepartmentsController : LookupBaseController<Department>
{

    private readonly IUowLookups UowLookups;

    public DepartmentsController(IUowLookups uowLookups) : base(uowLookups)
    {
        UowLookups = uowLookups;
    }

    [HttpPost] //Improvise on this
    [Route("getorderd")]
    public IEnumerable<Department> GetSelectedValues(List<string> ids)
    {
        
        var sortColumns = new Dictionary<string, Sorter>();

        sortColumns.Add("Code", new Sorter(1, SortDirection.Ascending));
        sortColumns.Add("Name", new Sorter(2, SortDirection.Ascending));

        IQueryable<Department> coll = Enumerable.Empty<Department>().AsQueryable();


        var sortExp2 = ExpressionBuilder.OrderByColumns<Department>(coll, sortColumns);

        var data = UowLookups.Repository<Department>().GetSelected(null, sortExp2 )
                                                                        
        return data.ToList();
    }
}

我有以下代码(在 Whosebug 中找到)运行良好。但是我想用下面的代码return(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>)代替集合。我也不希望将集合传递给此方法,相反,它应该将我传递的 TEntity 作为集合。可行吗?

public static IQueryable<TEntity> OrderByColumns<TEntity>(this IQueryable<TEntity> collection, IDictionary<string, Sorter> sortedColumns)
{
    // Basically sortedColumns contains the columns user wants to sort by, and 
    // the sorting direction.
    // For my screenshot, the sortedColumns looks like
    // [
    //     { "cassette", { Order = 1, Direction = SortDirection.Ascending } },
    //     { "slotNumber", { Order = 2, Direction = SortDirection.Ascending } }
    // ]

    bool firstTime = true;

    // The type that represents each row in the table
    var itemType = typeof(TEntity);

    // Name the parameter passed into the lamda "x", of the type TModel
    var parameter = Expression.Parameter(itemType, "x");

    // Loop through the sorted columns to build the expression tree
    foreach (var sortedColumn in sortedColumns.OrderBy(sc => sc.Value.Order))
    {
        // Get the property from the TModel, based on the key
        var prop = Expression.Property(parameter, sortedColumn.Key);

        // Build something like x => x.Cassette or x => x.SlotNumber
        var exp = Expression.Lambda(prop, parameter);

        // Based on the sorting direction, get the right method
        string method = String.Empty;
        if (firstTime)
        {
            method = sortedColumn.Value.Direction == SortDirection.Ascending
                ? "OrderBy"
                : "OrderByDescending";

            firstTime = false;
        }
        else
        {
            method = sortedColumn.Value.Direction == SortDirection.Ascending
                ? "ThenBy"
                : "ThenByDescending";
        }

        // itemType is the type of the TModel
        // exp.Body.Type is the type of the property. Again, for Cassette, it's
        //     a String. For SlotNumber, it's a Double.
        Type[] types = new Type[] { itemType, exp.Body.Type };

        // Build the call expression
        // It will look something like:
        //     OrderBy*(x => x.Cassette) or Order*(x => x.SlotNumber)
        //     ThenBy*(x => x.Cassette) or ThenBy*(x => x.SlotNumber)
        var mce = Expression.Call(typeof(Queryable), method, types,
            collection.Expression, exp);

        // Now you can run the expression against the collection
        collection = collection.Provider.CreateQuery<TEntity>(mce);
    }

    return collection;
}

答案很简单:

public static Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> CreateOrderByFunc<TEntity>(IDictionary<string, Sorter> sortedColumns)
{
   return q => (IOrderedQueryable<TEntity>)q.OrderByColumns(sortedColumns);
}