我正在尝试构建一个将Paginated查询的扩展方法。 但为了避免异常: 用户代码未处理System.NotSupportedException Message =方法'Skip'仅支持LINQ to Entities中的排序输入。必须在方法'Skip'之前调用'OrderBy'方法。
我想检查是否已应用OrderBy,如果不是,则只返回查询... 像这样:
public static IQueryable<T> Paginate<T>(this IQueryable<T> query, int page, int pageSize = 50, int total = -1)
{
// check if OrderBy was applied
// THIS DOES NOT WORK!!!
//try
//{
// var orderedQueryable = query as IOrderedQueryable<T>;
//}
//catch (Exception)
//{
// // if the cast throws OrderBy was not applied <-- DOES NOT WORK!!!
// return query;
//}
page = (page < 1) ? 1 : page;
var limit = (pageSize <= 0 || (total >= 0 && pageSize > total)) ? 50 : pageSize;
var skip = (page - 1)*limit;
return query.Skip(skip).Take(limit);
}
为了让事情变得更有趣,我正在使用Mycrosoft的Dynamic Expression API(又名动态LINQ),所以我的调用代码看起来像
return query
.OrderBy("Customer.LastName DESC, Customer.FirstName")
.Paginate(1,25, 2345)
.ToArray();
或者我可以使用像这样的强类型表达式来调用它
return query
.OrderByDescending(c=>c.LastName)
.ThenBy(c=>c.FirstName)
.Paginate(1,25,2345)
.ToArray();
这种检查是否可行?
我厌倦了在方法签名中使用IOrderableQueryable<T>
但是当您使用OrderBy(字符串表达式)时,Dynamic Linq不会返回IOrderableQueryable
,因此扩展将不适用...
使用建议(由@GertArnold指出)唯一可行的解决方案是检查表达式树。但是,不要使用整个ExpressionVisitor
,而是通过要求必须在OrderBy
或OrderByDescending
之后调用Paginate方法来简化我的解决方案。这使我只能检查表达式树中的当前节点,而不是搜索整个树。
所以这就是我所做的:
// snip....class level
private static readonly string[] PaginationPrerequisiteMehods = new[] { "OrderBy", "OrderByDescending" };
// snip Paginate method
public static IQueryable<T> Paginate<T>(this IQueryable<T> query, int page, int pageSize = 50, int total = -1)
{
// require that either OrderBy or OrderByDescending was applied just before calling Paginate....
if (query.Expression.NodeType != ExpressionType.Call)
{
//TODO: logging -> "You have to apply OrderBy() or OrderByDescending() just before calling Paginate()"
return query;
}
var methodName = ((MethodCallExpression) query.Expression).Method.Name;
if (!Array.Exists(PaginationPrerequisiteMehods, s => s.Equals(methodName, StringComparison.InvariantCulture)))
{
//TODO: logging -> "You have to apply OrderBy() or OrderByDescending() just before calling Paginate()"
return query;
}
page = (page < 1) ? 1 : page;
var limit = (pageSize <= 0 || (total >= 0 && pageSize > total)) ? 50 : pageSize;
var skip = (page - 1)*limit;
return query.Skip(skip).Take(limit);
}
答案 0 :(得分:2)
答案 1 :(得分:1)
不知何故,看起来你正试图解决一些没有意义的事情。
使用方法时,您不希望获得运行时异常。好!但在这种情况下,请不要使用Dynamic Linq,因为这正是导致运行时异常并为IOrderedQueryable
方法使用Paginate
的原因。
您想使用Dynamic Linq。好!但在这种情况下,您需要一些测试(我的意思是集成测试),它将在运行时测试您的代码,并且您的Paginate
方法应该以相同的方式进行测试。
在运行时探索表达式树仍然与运行时异常相同 - 它没有通知程序员在无序数据上使用Paginate方法。