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

时间:2016-05-30 08:22:24

标签: c# asp.net-core-mvc entity-framework-core

这是表

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时,它工作正常。 有谁可以帮助我?

1 个答案:

答案 0 :(得分:0)

好的,这只是尝试使用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问题。 它解决了内存中的“复杂”解决方案。有时成本必须在某个地方,并且在内存中总和优于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,因为它的功能可以更好地转换为SQL 同样在构造函数中将集合初始化为new HashSet<T>(),因此您不会以null异常结束。可以这样想,你不能计算null的元素,但你可以用0行计算集合的元素。

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