如何将此 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; }
}
这是表格
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; }
}