使用不同的键 .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
排序,但我如何使用例如LastName
、Address
等等...?
试试这个扩展方法:
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);
}
并且您可以将 属性 名称作为字符串传递,例如 FirstName
、LastName
或 Address
等。因此您可以动态地订购 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
我在前端有一个 table,有多个列和分页。用户应该能够对他想要的列进行排序,如果他移动到下一页,该页面也应该按给定的列排序。
我使用单个排序键和分页的方法:
public List<Person> GetPersons(int page, int numPerPage)
{
return _context.Person
.OrderByDescending(p => p.FirstName)
.Skip(page*numPerPage)
.Take(numPerPage)
}
这仅限于按 FirstName
排序,但我如何使用例如LastName
、Address
等等...?
试试这个扩展方法:
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);
}
并且您可以将 属性 名称作为字符串传递,例如 FirstName
、LastName
或 Address
等。因此您可以动态地订购 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