C# 使Linq to Sql使用ISNULL而不是COALESCE生成T-Sql

C# 使Linq to Sql使用ISNULL而不是COALESCE生成T-Sql,c#,linq,tsql,linq-to-sql,C#,Linq,Tsql,Linq To Sql,我有一个linq到sql查询,它返回一些非零余额的订单(事实上,查询有点复杂,但为了简单起见,我省略了一些细节)。这个查询还应该返回没有carditem的订单(在T-SQL中,两个子查询都返回NULL,比较两个NULL会得到FALSE,因此我将子查询的NULL结果值转换为0进行比较) 问题在于,转换表达式Sum(i=>(double?)i.Amount)??0生成COALESCE运算符,该运算符的速度比完全相同的T-SQL查询慢十倍,替换后的COALESCE to为null,因为其中包含子查询。

我有一个linq到sql查询,它返回一些非零余额的订单(事实上,查询有点复杂,但为了简单起见,我省略了一些细节)。这个查询还应该返回没有carditem的订单(在T-SQL中,两个子查询都返回NULL,比较两个NULL会得到FALSE,因此我将子查询的NULL结果值转换为0进行比较)


问题在于,转换表达式Sum(i=>(double?)i.Amount)??0生成COALESCE运算符,该运算符的速度比完全相同的T-SQL查询慢十倍,替换后的COALESCE to为null,因为其中包含子查询。在这种情况下是否有可能生成ISNULL

因为您假设一个没有数量的行被求和为零,那么您只需过滤掉没有数量的行,而不用担心IsNull或coalesce

&& 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)

由于我不知道您的对象,您甚至可以删除强制转换(double?)和默认(??)运算符,以我的经验来看,诱使linq生成所需的SQL充其量只是一件麻烦事。如果您有一个比linq更好的查询实现(工作正确且性能良好),那么继续使用它,即使只是针对这一个查询

最快的方法可能是使用
DataContext.ExecuteQuery
。它甚至会为您生成和处理返回的对象,就像linq自己生成查询一样

许多人宁愿将此SQL放在存储过程中,尤其是在生产代码中。然后只需将存储过程映射到linq对象中,其工作方式与此相同。通常情况下,ScottGu有一篇关于如何做到这一点的相当详细的帖子:


@PreetSangha,如果你知道问题出在哪里,那么用正确的方式编写代码“错”在哪里?我认为一个错误的方法,即使你知道这个问题,你也不会做任何事情…如果您愿意生成一个比实际速度慢10倍的代码,那么将优化称为“错误”是非常有趣的。@walther:许多其他人已经说过为什么过早优化是有害的。OP:查询的总体运行时间是否受到显著影响?这应该指导你是否应该重视这一点,而不是你以前与操作员的经验。@Guvante和许多其他人都说过,为什么愿意用“我以后可能会解决它”这个词编写一个糟糕的代码是一个糟糕的方法。。。如果你知道你的代码是坏的,不要等到它成为一个问题。。。就我的意见而言,也许你喜欢以后再解决问题:)@walther:除非出现实际的性能问题,否则没有什么需要解决的。我没有看到任何实际的性能测试表明,
COALESCE
导致了他的问题,只是他说他听说这样做不好。在任何一种情况下,他都不应该做那样的事情(正如Oblivion2000的回答所显示的),所以这是一个没有实际意义的观点。伙计们,OP已经清楚地表明,在他的情况下,ISNULL更可取。要么给他一个解决办法,要么回答问题!无需进一步争辩。如果删除空合并??运算符,您的查询将不会返回没有carditem的订单(SUM运算符将返回NULL,与NULL进行比较总是返回FALSE),它将与
和&p.SUM+(db.CardItems.Where(i=>i.IncomeId==p.Id).SUM(i=>i.Amount))相等(db.CardItems.Where(i=>i.decluted==p.Id).Sum(i=>i.Amount)
。如果将??放在原处,它将不会提供任何优势,因为生成的T-SQL与origin几乎相同。问题不在于NULL Amount,此列甚至不可为NULL,而在于NULL Sum。
&& 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)