我有一个旧版.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 ...
这些是到诸如ReceiptLines的表的映射,这些表引用了此Item对象。
第二次编辑
我做了一些数据库工作,下面的查询示例与应该做的非常接近(有一些调整)。
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中实现它
答案 0 :(得分:1)
您可以异步调用所有查询,并在所有查询完成后计算总和。
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();
答案 1 :(得分:0)
使用我的SQL to LINQ Recipe,您的SQL查询(对未指定的数据库到类的映射有一些假设)将转换为:
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
};