LINQ to SQL – 为什么不能在ORDER BY之后使用WHERE?
以下代码:
// 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的设计原因是,在使用运营商order by
后无法添加where
约束?
OrderBy
的返回类型是IOrderedQueryable
,因此这是orders
变量的类型(部分原因是你在末尾有一个无操作投影) – 但Where
的返回类型只是IQueryable
。 基本上你有一个无操作投影和隐式类型局部变量的混合,查询的最后一个活动部分是一个排序, 然后你想要重新分配变量。 基本上,这是一个不愉快的组合。
你可以像这样解决它:
IQuerable 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)); }
或者作为一个最终的,有点奇怪的建议,你可以改变你的初始where
和orderby
子句的顺序。 这在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设计的“原因”而言: OrderBy
和OrderByDescending
返回IOrderedQueryable
以便您可以使用ThenBy
和ThenByDescending
链接它,它依赖于现有的订单,它们可以成为次要的,如果你看到我的话意思。
重要的是要注意var是强类型的并且在编译时被解释。 您的第一个代码段基本上与以下内容相同:
IOrderedQueryable 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