public class Branch
{
[Sortable(OrderBy = "BranchId")]
public long BranchId { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public string Type { get; set; }
}
这是我的Model类,我还创建了一个自定义属性
public class SortableAttribute : Attribute
{
public string OrderBy { get; set; }
}
现在我用orderby降序创建分页,但是此代码不起作用
public static async Task<IPagedList<T>> ToPagedListAsync<T>(this IQueryable<T> source,
GeneralPagingRequest pagingRequest, int indexFrom = 0,
CancellationToken cancellationToken = default(CancellationToken))
{
if (indexFrom > pagingRequest.PageNumber)
{
throw new ArgumentException(
$"indexFrom: {indexFrom} > pageNumber: {pagingRequest.PageNumber}, must indexFrom <= pageNumber");
}
var count = await source.CountAsync(cancellationToken).ConfigureAwait(false);
var items = source.Skip(((pagingRequest.PageNumber - 1) - indexFrom) * pagingRequest.PageSize)
.Take(pagingRequest.PageSize);
var props = typeof(T).GetProperties();
PropertyInfo orderByProperty;
orderByProperty =
props.FirstOrDefault(x=>x.GetCustomAttributes(typeof(SortableAttribute), true).Length != 0);
if (pagingRequest.OrderBy == "desc")
{
items = items.OrderBy(x => orderByProperty.GetValue(x));
}
else
{
items = items.OrderBy(x => orderByProperty.GetValue(x));
}
var result = await items.ToListAsync(cancellationToken).ConfigureAwait(false);
var pagedList = new PagedList<T>
{
PageNumber = pagingRequest.PageNumber,
PageSize = pagingRequest.PageSize,
IndexFrom = indexFrom,
TotalCount = count,
Items = result,
TotalPages = (int) Math.Ceiling(count / (double) pagingRequest.PageSize)
};
return pagedList;
}
但结果变量创建异常
答案 0 :(得分:0)
.OrderBy()
需要一个委托,该委托将告诉它 HOW (选择),而不是键值本身。因此,您正在这里查看一些元编程。
自然地,您将看到构建动态的LINQ表达式树,该树将为您获取属性:
// your code up above
PropertyInfo orderByProperty = props.FirstOrDefault(x => x.GetCustomAttributes(typeof(SortableAttribute), true).Length != 0);
var p = Expression.Parameter(typeof(T), "x"); // you define your delegate parameter here
var accessor = Expression.Property(p, orderByProperty.GetMethod); // this basically becomes your `x => x.BranchId` construct
var predicate = Expression.Lambda(accessor, p).Compile(); // here's our problem: as we don't know resulting type at compile time we can't go `Expression.Lambda<T, long>(accessor, p)` here
if (pagingRequest.OrderBy == "desc")
{
items = items.OrderByDescending(x => predicate(x)); // passing a Delegate here will not work as OrderBy requires Func<T, TKey>
}
else
{
items = items.OrderBy(x => predicate(x)); // passing a Delegate here will not work as OrderBy requires Func<T, TKey>
}
var result = await items.ToListAsync(cancellationToken).ConfigureAwait(false);
// your code down below
上面的代码存在问题-您不预先知道TKey
。因此,我们将不得不更深入,并动态地构建整个items.OrderBy(x => x.BranchId)
表达式。信念的最大飞跃将是OrderBy
是一种扩展方法,它实际上驻留在IQueryable
类型上。在获得通用方法参考之后,您将需要在知道属性类型时构建特定的委托类型。这样您的方法就变成这样:
public static class ExtToPagedListAsync
{
private static readonly MethodInfo OrderByMethod = typeof(Queryable).GetMethods().Single(method => method.Name == "OrderBy" && method.GetParameters().Length == 2); // you need your method reference, might as well find it once
private static readonly MethodInfo OrderByDescendingMethod = typeof(Queryable).GetMethods().Single(method => method.Name == "OrderByDescending" && method.GetParameters().Length == 2); // you need your method reference, might as well find it once
public static async Task<IPagedList<T>> ToPagedListAsync<T>(this IQueryable<T> source, GeneralPagingRequest pagingRequest, int indexFrom = 0, CancellationToken cancellationToken = default(CancellationToken))
{
if (indexFrom > pagingRequest.PageNumber)
{
throw new ArgumentException(
$"indexFrom: {indexFrom} > pageNumber: {pagingRequest.PageNumber}, must indexFrom <= pageNumber");
}
var count = await source.CountAsync(cancellationToken).ConfigureAwait(false);
var items = source.Skip(((pagingRequest.PageNumber - 1) - indexFrom) * pagingRequest.PageSize)
.Take(pagingRequest.PageSize);
var props = typeof(T).GetProperties();
PropertyInfo orderByProperty = props.FirstOrDefault(x => x.GetCustomAttributes(typeof(SortableAttribute), true).Length != 0);
var p = Expression.Parameter(typeof(T), "x");
var accessor = Expression.Property(p, orderByProperty.GetMethod);
var predicate = Expression.Lambda(accessor, p); // notice, we're not yet compiling the predicate. we still want an Expression here
// grab the correct method depending on your condition
MethodInfo genericMethod = (pagingRequest.OrderBy == "desc") ? OrderByDescendingMethod.MakeGenericMethod(typeof(T), orderByProperty.PropertyType)
:OrderByMethod.MakeGenericMethod(typeof(T), orderByProperty.PropertyType);
object ret = genericMethod.Invoke(null, new object[] { items, predicate });
items = (IQueryable<T>)ret; // finally cast it back to Queryable with your known T
var result = await items.ToListAsync(cancellationToken).ConfigureAwait(false);
var pagedList = new PagedList<T>
{
PageNumber = pagingRequest.PageNumber,
PageSize = pagingRequest.PageSize,
IndexFrom = indexFrom,
TotalCount = count,
Items = result,
TotalPages = (int)Math.Ceiling(count / (double)pagingRequest.PageSize)
};
return pagedList;
}
}
我必须透露我确实从this answer here得到了一些启发,因此请检查一下以供进一步阅读。