我有一些具有冗余的
linq查询,我想分解出一段代码.这些是IQueryable的连接表达式,重要的是我不会导致查询比没有重构时更早地进行评估.
这是一个简化的查询:
var result = from T in db.Transactions join O in db.Orders on T.OrderID equals O.OrderID join OD in db.OrderDetails on O.OrderID equals OD.OrderID into OrderDetails let FirstProductBought = OrderDetails.First().Select(OD => OD.Product.ProductName) select new { TransactionID = T.TransactionID,OrderID = O.OrderID,FirstProductBought = FirstProductBought };
我想要分解的是“给定订单,购买的第一个产品是什么”的逻辑.我在其他查询中使用相同的逻辑.如何将其分解为共享方法?
通常,对于代码重用和IQueryables,我能够做的是使IQueryable进入并生成IQueryable / IOrderedQueryable作为输出的代码.有了这些函数,我可以使用可重用的代码构建LINQ表达式,这些代码仍然会延迟查询,直到查询完全构造完毕.在这里,由于我只有一个int(orderID),我不知道如何让它工作.
谢谢
解决方法
很抱歉回答我自己的问题,但我找到了一个很好的解决方案.我认为,根据你想要做的事情,有不同的方法来分析不同的LINQ表达式而不评估IQueryable.所以我希望人们分享替代解决方案.
我的解决方案是为分解的查询创建一个“视图”.我将其称为视图,因为它与sql视图有很多共同点(从LINQ客户端的角度来看).但是,与sql视图不同,它无法编入索引或持久保留列.因此,使用此视图成为瓶颈,使用实际的sql视图是合适的.
static public class MyDataContextExtension { // The view exposes OrderSummary objects public class OrderSummary { public OrderID { get; set; } public string FirstProductListed { get; set; } } static public IQueryable<OrderSummary> OrderySummaryView(this MyDataContext db) { return ( from O in db.Orders join OD in db.OrderDetails on O.OrderID equals OD.OrderID into OrderDetails let AProductBought = OrderDetails.First().Select(OD => OD.Product.ProductName) let TotalCost = OrderDetails.Aggregate(0 select new OrderSummary() { OrderID = OD.OrderID,FirstProductListed = AProductBought.FirstOrDefault() }; } }
有了这个,我可以分解查询的重复部分,用以下内容替换原始查询:
var result = from T in db.Transactions join OS in db.OrderSummaryView() on T.OrderID equals OS.OrderID select new { TransactionID = T.TransactionID,OrderID = T.OrderID,FirstProductBought = OS.FirstProductListed };
您可以想象添加其他列…我认为一个很酷的事情是,如果您添加额外的列但不在最终选择中使用它们,LINQ实际上不会从数据库中查询这些内容.