我有一个linq to sql查询返回一些非零余额的订单(实际上,查询有点复杂,但为了简单起见,我省略了一些细节)。此查询还应返回没有CardItems的订单(两个子查询在T-SQL中都返回NULL,并且比较两个NULLS给出FALSE,因此我将子查询的NULL结果值转换为0以进行比较)。
var q = (from o in db.Orders
where db.Cards(p =>
p.OrderId == o.Id
&& p.Sum + (db.CardItems.Where(i => i.IncomeId == p.Id)
.Sum(i => (double?)i.Amount) ?? 0)
!= (db.CardItems.Where(i => i.DeductId == p.Id)
.Sum(i => (double?)i.Amount) ?? 0)
).Any()
select o);
问题是,转换表达式Sum(i =>(double?)i.Amount)?? 0 生成COALESCE 运算符,由于其中的子查询,将COALESCE替换为 ISNULL 的完全相同的T-SQL查询慢十倍。在这种情况下是否有可能生成ISNULL?
答案 0 :(得分:2)
根据我的经验,哄骗linq生成你想要的SQL是最好的麻烦。如果你有一个比linq更好的查询实现(正常工作并且运行良好),请继续使用它,即使只针对这一个查询。
最快的方式可能是DataContext.ExecuteQuery<TResult>
。它甚至会为你返回水合并处理返回的对象,就像linq生成查询本身一样。
http://msdn.microsoft.com/en-us/library/bb361109.aspx
许多人宁愿将此SQL放在存储过程中,尤其是在生产代码中。然后,您只需将存储过程映射到linq对象中,它的工作方式相同。通常情况下,ScottGu有一篇关于如何做到这一点的相当详细的文章:
答案 1 :(得分:0)
由于假设没有Amount的行被归为零,那么你可以只过滤掉没有金额的行,而不用担心IsNull或合并。
&& p.Sum + (db.CardItems.Where(i => i.IncomeId == p.Id)
.Where(i=> i.Amount > 0)
.Sum(i => (double?)i.Amount) ?? 0)
!= (db.CardItems.Where(i => i.DeductId == p.Id)
.Where(i=> i.Amount > 0)
.Sum(i => (double?)i.Amount) ?? 0)
由于我不知道你的对象,你甚至可以删除强制转换(双?)和默认(??)运算符