确定是否已订购IQueryable <t> </t>

时间:2011-12-14 16:13:01

标签: c# sql-order-by iqueryable

有没有办法知道是否已订购IQueryable<T>(使用OrderByOrderbyDescending)?

所以我知道是否要在集合上调用OrderByThenBy

IQueryable<Contact> contacts = Database.GetContacts();

我尝试了contacts is IOrderedQueryable<Contact>,但它始终是真的。

编辑:我刚刚改变了我的例子,前一个没有真正表明我的观点。假设GetContacts使用Entity Framework并简单地返回表的所有记录。

稍后,我将几个函数应用于contacts,我不知道这些函数的作用。他们可以对IQueryable<Contact>进行排序或过滤。

当我收回集合时,我需要再次对它进行排序。为此,我需要知道是否需要致电OrderByThenBy。因此,如果整个集合已经排序,我不会重新排序。

7 个答案:

答案 0 :(得分:24)

这是可能的。这是一种扩展方法:

public static bool IsOrdered<T>(this IQueryable<T> queryable)
{
    if (queryable == null)
    {
        throw new ArgumentNullException("queryable");
    }

    return queryable.Expression.Type == typeof(IOrderedQueryable<T>);
}

答案 1 :(得分:3)

是的,您可以检查IQueryable.Expression树以查看它是否调用任何OrderBy/ThenBy方法。可以通过从ExpressionVisitor派生类来检查表达式树。

System.Web中有一个内部OrderingMethodFinder - 您可以调整它。这就是我想出的:

// Adapted from internal System.Web.Util.OrderingMethodFinder http://referencesource.microsoft.com/#System.Web/Util/OrderingMethodFinder.cs
class OrderingMethodFinder : ExpressionVisitor
{
    bool _orderingMethodFound = false;

    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        var name = node.Method.Name;

        if (node.Method.DeclaringType == typeof(Queryable) && (
            name.StartsWith("OrderBy", StringComparison.Ordinal) ||
            name.StartsWith("ThenBy", StringComparison.Ordinal)))
        {
            _orderingMethodFound = true;
        }

        return base.VisitMethodCall(node);
    }

    public static bool OrderMethodExists(Expression expression)
    {
        var visitor = new OrderingMethodFinder();
        visitor.Visit(expression);
        return visitor._orderingMethodFound;
    }
}

像这样使用它:

bool isOrdered = OrderingMethodFinder.OrderMethodExists(myQuery.Expression);

答案 2 :(得分:1)

除非您自己检查订购,否则您永远不会知道对象是否已正确订购。您的示例很容易看出它们没有被排序,因为数字具有自然顺序,但IQueryable是通用的,这意味着它可以处理不同类型的对象。说用户对象(FirstName,LastName,DateStart和LastPayDate)的顺序具有任意顺序,因此返回它们的顺序不一定是您要查找的顺序。 (这被认为是排序的主要领域?这取决于你的需要。)因此,理论上,“他们订购了”这个问题总是“是的!”您要查找的订单可能与系统返回的订单大不相同。

答案 3 :(得分:1)

简短回答是否定的,Queryable类没有维护标志,也没有对集合进行排序,也没有使用什么方法来执行这样的排序。

http://msdn.microsoft.com/en-us/library/system.linq.queryable.aspx

答案 4 :(得分:1)

实际上,你可以。

我在您的代码中发现的第一个问题是,您无需任何理由将该集合转换为IQueryable

以下代码段:

var numbers = new[] {1, 5, 6, 87, 3};
Console.Write(numbers is IOrderedEnumerable<int>);
var ordered = numbers.OrderBy(c => c);
Console.Write(ordered is IOrderedEnumerable<int>);

甚至不需要运行:第一次检查会给你一个设计时间警告,说明这个表达式永远不会成真。

无论如何,如果你运行它,它会在第一次检查时给你False,在第二次检查时会给你。

您可以使用IQueryable<T>IOrderedQueryable<T>执行相同的操作,只要您真正使用该类型,而不是向其投射集合。

答案 5 :(得分:1)

您可以检查查询的ToString()以查明是否使用了Order By。

当连接发生时,IQueryable的ToString将parantheses放入内部查询的begininng和end。因此,如果您找到最后一个关闭的parantheses,您可以检查您的最外层查询是否具有Order By子句。

    private bool isOrdered(IQueryable Data)
    {
        string query = Data.ToString();

        int pIndex = query.LastIndexOf(')');

        if (pIndex == -1)
            pIndex = 0;

        if (query.IndexOf("ORDER BY", pIndex) != -1)
        {
            return true;
        }

        return false;
    }

我知道它非常脏,但它适用于我的所有情况,我想不出一个例外情况。

答案 6 :(得分:0)

这对我有用。

对IQueryable列表进行排序(排序依据)时,其类型从IQueryable更改为IOrderedQueryable。

if (iQueryableList.Expression.Type == typeof(IOrderedQueryable<T>))
{
    //IQueryable is sorted
}
else
{
    //IQueryable is sorted
}

您可以在下面的帖子中找到关于此的更多详细信息。

more details