重构LINQ IQueryable表达式以删除重复的查询部分

Fra*_*man 7 .net linq iqueryable linq-to-sql

我有一些具有冗余的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
};
Run Code Online (Sandbox Code Playgroud)

我想要分解的是"给定订单,购买的第一个产品是什么"的逻辑.我在其他查询中使用相同的逻辑.如何将其分解为共享方法?

通常,对于代码重用和IQueryables,我能够做的是使IQueryable进入并生成IQueryable/IOrderedQueryable作为输出的代码.使用这些函数,我可以使用可重用代码构建LINQ表达式,该代码仍然会延迟查询,直到查询完全构造完毕.在这里,由于我只有一个int(orderID),我不知道如何使它工作.

谢谢

Fra*_*man 4

很抱歉回答我自己的问题,但我找到了一个很好的解决方案。我认为,根据您想要执行的操作,有不同的方法可以在不评估 IQueryable 的情况下分解出不同的 LINQ 表达式。所以我希望人们分享替代解决方案。

我的解决方案是为分解的查询创建一个“视图”。我将其称为视图是因为它与 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()
              };
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,我可以提取出查询的重复部分,用以下内容替换原始查询:

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
};
Run Code Online (Sandbox Code Playgroud)

您可以想象添加其他列...我认为一件很酷的事情是,如果您添加额外的列但不在最终选择中使用它们,LINQ 实际上不会从数据库中查询这些内容。