如何将此 sql 转换为 Linq(复杂 SUM)

How to Translate this sql to Linq (complicate SUM)

这是表格

public class Purchase
{
    public long Id { get; set; }
    public string WareName { get; set; }
    public int Count { get; set; }
    public DateTime BuyTime { get; set; }
    public IList<Inventory> Inventory { get; set; }
 }
public class Inventory
{
    public long Id { get; set; } 
    public long PurchaseId { get; set; }
    [ForeignKey(nameof(PurchaseId))]
    public Purchase Purchase { get; set; }

    public int SaledCount { get; set; }

}

我试着做这样的查询:

SELECT SUM(x.[icout]) AS icount FROM
(
    SELECT p.[Count] - ISNULL(
            (SELECT SUM(i.SaledCount) FROM Inventory AS i WHERE i.PurchaseId = p.Id )
            ,0) AS [icout]
    FROM Purchase AS p 
    WHERE p.WareName ='WareName5' AND
    (  
        p.[Count] - ISNULL((SELECT SUM(i.SaledCount) FROM Inventory AS i WHERE i.PurchaseId = p.Id ),0) > 0
    )
) AS x`
var left = _Db.Set<Purchase>().Include(p=>p.Inventory)
            .Where(p=>p.WareName == WareName)
            .Select(p => p.Count - p.Inventory.Sum(i => i.SaledCount)).Sum();

但是当我以真实数据库 (sqlite / sqlserver) 为目标时它不起作用。 当我使用 inMemoryDatabase 时它工作正常。 谁能帮帮我?

好的,这只是使用 let 的一次尝试,只是在我的 DNet Core 网站上尝试过,运行 很好(我没有和你一样的实体当然)。

var left = from purchase in _Db.Set<Purchase>().Include(p=>p.Inventory)
           where purchase != null && purchase.WareName == WareName
           let sum = purchase.Inventory.Sum(i => i.SaledCount ?? 0)
           select (purchase.Count - sum).Sum();'

这是一个直接的解决方案,不应给您带来 N+1 问题。 它解决了内存中的 "complex" 解决方案。有时成本必须在某个地方,并且在内存中总和优于 N+1

var left = (from purchase in _Db.Set<Purchase>().Include(p=>p.Inventory)
           where purchase != null && purchase.WareName == WareName
           select new ()
           {
               count = purchase.Count - sum,
               invCounts = purchase.Inventory.where(a=> a.SaledCount!= null).Select(a=> a.SaledCount);
           }).ToList().Select(a => a.count - invCounts.Sum());

备注 使用 ICollection 而不是 IList 因为它的特性 t运行 比 SQL 更好 同样在构造函数中将集合初始化为 new HashSet<T>() ,这样您就不会以空异常结束。可以这样想,你不能计算 null 的元素,但你可以计算 0 行的集合的元素。

public class Purchase
{
   public Purchase(){
      Inventory = new HashSet<Inventory>();
   }
   public ICollection<Inventory> Inventory { get; set; }
}