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)); } 

或者作为一个最终的,有点奇怪的建议,你可以改变你的初始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以便您可以使用ThenByThenByDescending链接它,它依赖于现有的订单,它们可以成为次要的,如果你看到我的话意思。

重要的是要注意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 

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