繁体   English   中英

如何组合多个命中不同关联映射的 LINQ 查询

[英]How do I combine multiple LINQ queries that hit different associated mappings

我有一个遗留的 .net 应用程序,其中某些代码试图总结某些相关数据库行的计数。 这是一种库存解决方案,可以将来自多个来源(物品收货、调整、退货等)的物品添加到系统中。

当前代码的性能不是很好,主要是因为它执行多个查询,每个关系一个查询并将它们添加到运行计数器。 这是在主项目类的代码中,因此它利用关系属性来开始每一行

count += ReceiptLines.Where(p => p.ItemReceipt.TxnDate < dt).Sum(p => p.Quantity);
count += AdjustmentLines.Where(p => p.Adjustment.TxnDate < dt).Sum(p => p.Quantity);
count += TransferLines.Where(p => p.Transfer.TxnDate < dt).Sum(p => p.Quantity);
count += ReturnLines.Where(p => p.Return.TxnDate < dt).Sum(p => p.Quantity);

这只是一个片段,因为代码有更多的输入和一些减少计数的行。 通常有大约 14 个不同的查询来计算这个值。

我希望如果我可以将所有这些都移动到一个查询中,它会使该方法的性能更高,但我对 .NET 和 LINQ 还很陌生,我不确定如何将它们组合成一个查询。

LINQ 是否有一种方法可以让我合并这些语句?

编辑以回答以下问题:

这就是在 Item 类(上面的代码所在的位置)上定义这些属性的方式

[global::System.Data.Linq.Mapping.AssociationAttribute(Name="Item_ReturnLine", Storage="_ReturnLines", ThisKey="ItemId", OtherKey="ItemId")]
        public EntitySet<ReturnLine> ReturnLines ... 

这些是对表的映射,如引用此 Item 对象的 ReceiptLines。

第二次编辑

我做了一些数据库工作,下面的查询示例非常接近应该是什么(有一些调整)。

select i.itemid as itemId
, ISNULL(irl.total, 0) + ISNULL( rl.total, 0) + ISNULL(ial.total, 0) + ISNULL( itl.total, 0) as total,
CacheQuantityOnHand
from item i
left join ( select itemid, sum(quantity) as total from ItemReceiptLine where TxnDate < SYSDATETIME() group by itemid) irl on i.itemid = irl.itemid
left join ( select itemid, sum(quantity) as total from ReturnLine where TxnDate < SYSDATETIME() group by itemid) rl on i.itemid = rl.itemid
left join ( select itemid, sum(QuantityDiff) as total from InventoryAdjustmentLine where TxnDate < SYSDATETIME() group by itemid) ial on i.itemid = ial.itemid
left join ( select itemid, sum(quantity) as total from InventoryTransferLine where TxnDate < SYSDATETIME() group by itemid) itl on i.itemid = itl.itemid

从我的测试来看,这似乎很快,但我仍然不确定如何在 LINQ 中实现它

您可以异步调用所有查询并在所有查询完成时计算总和。

var receiptLines = ReceiptLines.Where(p => p.ItemReceipt.TxnDate < dt).SumAsync(p => p.Quantity);
var adjustmentLines = AdjustmentLines.Where(p => p.Adjustment.TxnDate < dt).SumAsync(p => p.Quantity);
var transferLines = TransferLines.Where(p => p.Transfer.TxnDate < dt).SumAsync(p => p.Quantity);
var returnLines = ReturnLines.Where(p => p.Return.TxnDate < dt).SumAsync(p => p.Quantity);

await Task.WhenAll(receiptLines, adjustmentLines, transferLines, returnLines);

var count = receiptLines.Result + adjustmentLines.Result + transferLines.Result + returnLines.Result;

异步调用时,所有查询几乎同时执行。

由于所有查询都具有相同的返回类型 ( Task<int> ),因此您可以使用集合。

var queryTasks = new[]
{
    ReceiptLines.Where(p => p.ItemReceipt.TxnDate < dt).SumAsync(p => p.Quantity),
    AdjustmentLines.Where(p => p.Adjustment.TxnDate < dt).SumAsync(p => p.Quantity),
    TransferLines.Where(p => p.Transfer.TxnDate < dt).SumAsync(p => p.Quantity),
    ReturnLines.Where(p => p.Return.TxnDate < dt).SumAsync(p => p.Quantity)
};

await Task.WhenAll(queryTasks);

var count = queryTasks.Select(task => task.Result).Sum();

使用我的SQL to LINQ Recipe ,您的 SQL 查询(有一些关于未指定的 DB 到类映射的假设)将转换为:

var irlq = from r in ReceiptLines
           where r.ItemReceipt.TxnDate < dt
           group r by r.ItemId into rg
           select new {
               ItemId = rg.Key,
               Total = rg.Sum(r => r.Quantity)
           };
var rlq = from r in ReturnLines
          where r.Return.TxnDate < dt
          group r by r.ItemId into rg
          select new {
              ItemId = rg.Key,
              Total = rg.Sum(r => r.Quantity)
          };
var ialq = from r in AdjustmentLines
           where r.Adjustment.TxnDate < dt
           group r by r.ItemId into rg
           select new {
               ItemId = rg.Key,
               Total = rg.Sum(r => r.Quantity)
           };
var itlq = from r in TransferLines
           where r.Transfer.TxnDate < dt
           group r by r.ItemId into rg
           select new {
               ItemId = rg.Key,
               Total = rg.Sum(r => r.Quantity)
           };

var ans = from i in Items
          join irl in irlq on i.ItemId equals irl.ItemId into irlj
          from irl in irlj.DefaultIfEmpty()
          join rl in rlq on i.ItemId equals rl.ItemId into rlj
          from rl in rlj
          join ial in ialq on i.ItemId equals ial.ItemId into ialj
          from ial in ialj
          join itl in itlq on i.ItemId equals itl.ItemId into itlj
          from itl in itlj
          select new {
              i.ItemId,
              Total = (irl.Total ?? 0) + (rl.Total ?? 0) + (ial.Total ?? 0) + (itl.Total ?? 0)
            i.CacheQuantityOnHand
          };

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM