LINQ to SQL - 为什么不能在ORDER BY之后使用WHERE?

时间:2010-06-08 16:40:02

标签: c# linq linq-to-sql

以下代码:

// select all orders
var orders = from o in FoodOrders
             where o.STATUS = 1
             order by o.ORDER_DATE descending
             select o;

// if customer id is specified, only select orders from specific customer
if (customerID!=null)
{
    orders = orders.Where(o => customerID.Equals(o.CUSTOMER_ID));
}

给了我以下错误:

  

无法将类型'System.Linq.IQueryable'隐式转换为'System.Linq.IOrderedQueryable'。存在显式转换(您是否错过了演员?)

我通过在结尾处进行排序来修复错误:

// select all orders
var orders = from o in FoodOrders
             where o.STATUS = 1
             select o;

// if customer id is specified, only select orders from specific customer
if (customerID!=null)
{
    orders = orders.Where(o => customerID.Equals(o.CUSTOMER_ID));
}

// I'm forced to do the ordering here
orders = orders.OrderBy(o => o.ORDER_DATE).Reverse();

但我想知道为什么会出现这种限制?设计API的原因是,在使用where运算符后无法添加order by约束的原因是什么?

2 个答案:

答案 0 :(得分:12)

OrderBy的返回类型为IOrderedQueryable<T>,因此这是orders变量的类型(部分原因是您在结尾处有无操作投影) - 但返回类型Where只是IQueryable<T>。基本上你有一个无操作投影混合的隐式类型局部变量查询的最后一个活动部分是一个排序,和< / em>然后你想要重新分配变量。基本上,这是一个不愉快的组合。

你可以这样解决:

IQuerable<FoodOrders> orders = from o in FoodOrders
                               where o.STATUS == 1
                               order by o.ORDER_DATE descending
                               select o;

// if customer id is specified, only select orders from specific customer
if (customerID!=null)
{
    orders = orders.Where(o => customerID.Equals(o.CUSTOMER_ID));
}

或者,如果您使用点表示法明确地执行了无操作投影(我怀疑SQL转换器将足够聪明以应对!)类型推断可以正常:

var orders = FoodOrders.Where(o => o.STATUS == 1)
                       .OrderByDescending(o => o.ORDER_DATE)
                       .Select(o => o);

// if customer id is specified, only select orders from specific customer
if (customerID!=null)
{
    orders = orders.Where(o => customerID.Equals(o.CUSTOMER_ID));
}

或者作为一个最终且略显奇怪的建议,您只需更改初始whereorderby条款的顺序即可。这在LINQ to Objects中是一个坏主意,但不应该在LINQ to SQL中有所作为:

var orders = from o in FoodOrders
             order by o.ORDER_DATE descending
             where o.STATUS == 1
             select o;

// if customer id is specified, only select orders from specific customer
if (customerID!=null)
{
    orders = orders.Where(o => customerID.Equals(o.CUSTOMER_ID));
}

现在,就API设计的“原因”而言:OrderByOrderByDescending返回IOrderedQueryable,以便您可以使用ThenBy和{{ 1}}如果你明白我的意思,它依赖于现有的顺序,它们可以成为次要的。

答案 1 :(得分:4)

重要的是要注意var是强类型的并且在编译时被解释。您的第一个代码段基本上与:

相同
IOrderedQueryable<FoodOrders> orders = from o in FoodOrders 
         where o.STATUS = 1 
         order by o.ORDER_DATE descending 
         select o; 

当你以这种方式编写代码时,很明显为什么你不能将IQueryable分配给声明为IOrderedQueryable的变量。

你不能以与对象

相同的方式来考虑var
object aString = "Testing...";
var bString = "Testing...";

aString = 1; // Works
bString = 1; // Fails because 1 is not a string

http://msdn.microsoft.com/en-us/library/bb384061.aspx