使用不同的键 .net 进行排序和过滤

Sort and filter with varying key .net

我在前端有一个 table,有多个列和分页。用户应该能够对他想要的列进行排序,如果他移动到下一页,该页面也应该按给定的列排序。

我使用单个排序键和分页的方法:

public List<Person> GetPersons(int page, int numPerPage)
{
   return _context.Person
                  .OrderByDescending(p => p.FirstName)
                  .Skip(page*numPerPage)
                  .Take(numPerPage)
}

这仅限于按 FirstName 排序,但我如何使用例如LastNameAddress 等等...?

试试这个扩展方法:

public static IQueryable<T> OrderByField<T>(this IQueryable<T> q, string SortField, bool Ascending)
{
    var param = Expression.Parameter(typeof(T), "p");
    var prop = Expression.Property(param, SortField);
    var exp = Expression.Lambda(prop, param);
    string method = Ascending ? "OrderBy" : "OrderByDescending";
    Type[] types = new Type[] { q.ElementType, exp.Body.Type };
    var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp);
    return q.Provider.CreateQuery<T>(mce);
}

并且您可以将 属性 名称作为字符串传递,例如 FirstNameLastNameAddress 等。因此您可以动态地订购 Persons

public List<Person> GetPersons(int page, int numPerPage, string orderFieldName)
{
   return _context.Person
                  .OrderByField(orderFieldName, false)
                  .Skip(page*numPerPage)
                  .Take(numPerPage)
}

参见:How to use expression trees to build dynamic queries

编辑:

另一种可能的解决方案是使用 System.Linq.Dynamic 参见:

OrderByDescending 采用具有 2 个类型参数的函数:Expression<Func<TSource, TKey>> 其中 TKey 表示表达式返回的键的类型。

因此,您可以将表达式传递给您的方法并在 OrderBy 中使用:

public List<Person> GetPersons<TKey>(int page, int numPerPage, 
                                     Expression<Func<Person, TKey>> orderByDesc)
{
    return _context.Person
                   .OrderByDescending(orderByDesc)
                   .Skip(page*numPerPage)
                   .Take(numPerPage);
}

TKey 类型参数由表达式推断。所以,它可以像下面这样使用:

var byName = GetPersons(page, pageSize, p => p.FirstName);
var byDate = GetPersons(page, pageSize, p => p.DateOfBirth);
var byHeight = GetPersons(page, pageSize, p => p.Height);

如果要应用 filter/search,则向该方法添加一个新表达式并使用 Where:

public List<Person> GetPersons<TKey>(int page, int numPerPage,
                                     Expression<Func<Person, bool>> filter,
                                     Expression<Func<Person, TKey>> orderByDesc)
{
    return _context.Person
                   .Where(filter)
                   .OrderByDescending(orderByDesc)
                   .Skip(page*numPerPage)
                   .Take(numPerPage);
}
// filter by FirstName, order by LastName
var filtered = GetPersons(page, pageSize, 
                 p => p.FirstName == "Bob", // filter
                 p => p.LastName);          // orderBy