如何知道OrderBy是否应用于查询?

时间:2016-04-28 19:30:57

标签: c# entity-framework linq

我需要知道在应用.Skip或.Take之前是否将OrderBy应用于Linq查询。我无法控制收到的查询,如果应用了OrderBy,我需要维护这个,在任何其他情况下我应该OrderBy(t => true)。我尝试过以下方法:

    DataContext db;
    var query = db.Orders;

    var wasOrderByApplied = typeof(IOrderedQueryable<Order>).IsAssignableFrom(query.AsQueryable().Expression.Type);
    var wasOrderByApplied2 = query.AsQueryable().Expression.Type == typeof(System.Data.Entity.Core.Objects.ObjectQuery<Order>);
    var wasOrderByApplied3 = typeof(IOrderedQueryable<Order>) == query.AsQueryable().Expression.Type;

    var query2 = db.Orders.OrderBy(o => o.CreationDate);

    var wasOrderByApplied4 = typeof(IOrderedQueryable<Order>).IsAssignableFrom(query2.AsQueryable().Expression.Type);
    var wasOrderByApplied5 = query2.AsQueryable().Expression.Type == typeof(System.Data.Entity.Core.Objects.ObjectQuery<Order>);
    var wasOrderByApplied6 = typeof(IOrderedQueryable<Order>) == query2.AsQueryable().Expression.Type;

    var query3 = db.Orders.OrderBy(o => o.CreationDate).Where(o => o.Id > 4);

    var wasOrderByApplied7 = typeof(IOrderedQueryable<Order>).IsAssignableFrom(query3.AsQueryable().Expression.Type);
    var wasOrderByApplied8 = query3.AsQueryable().Expression.Type == typeof(System.Data.Entity.Core.Objects.ObjectQuery<Order>);
    var wasOrderByApplied9 = typeof(IOrderedQueryable<Order>) == query3.AsQueryable().Expression.Type;

结果在哪里:

wasOrderByApplied = true;
wasOrderByApplied2 = true;
wasOrderByApplied3 = false;

wasOrderByApplied4 = true;
wasOrderByApplied5 = false;
wasOrderByApplied6 = true;

对于最后的结果,似乎每个查询询问的第三个问题是正确的,但后来我做了第三个查询(query3)并且结果在哪里:

wasOrderByApplied7 = false;
wasOrderByApplied8 = false;
wasOrderByApplied9 = false;

当我在订单后面添加一个位置时,问题结果为 false ,其中 true

有没有更好的方法来了解OrderBy是否应用于查询?

2 个答案:

答案 0 :(得分:6)

这是我想到的一种可能的解决方案:

创建一个表达式访问者,检查表达式是否像这样调用OrderByOrderByDescending方法:

public class MyVisitor : ExpressionVisitor
{
    public bool HasOrderBy { get; private set; }

    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        if (node.Method.DeclaringType == typeof (Queryable) &&
            (node.Method.Name == "OrderBy" || node.Method.Name == "OrderByDescending"))
            HasOrderBy = true;

        return base.VisitMethodCall(node);
    }
}

以下是如何使用它:

MyVisitor visitor = new MyVisitor();

visitor.Visit(query.Expression);

if (visitor.HasOrderBy)
{
    //..
}
else
{
    //..
}

答案 1 :(得分:0)

你不需要知道什么。这毫无意义。如果您想要TakeSkip某些元素,您需要在此之前订购它们。请考虑以下

class Animal
{
    public int Weight { get; set; }
    public int NumberOfLegs { get; set; }
}

...

public IEnumerable<Animal> TakeFive(IEnumerable<Animal> animals)
{
    return animals.Take(5);
}

你会带五个动物?什么腿最多?还是那些更重的?还是那些重量较轻的?你不知道。但是,如果你改变这样的代码

public IEnumerable<Animal> TakeFive(IEnumerable<Animal> animals)
{
    return animals.OrderBy(_ => .Weight).Take(5);
}

它开始有道理了。

您不仅可以将其应用于IEnumerable,还可以应用于IQueryable。如果您不知道订单是什么,则无需知道序列是否已订购。