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

时间:2012-06-08 11:45:32

标签: c# linq tsql linq-to-sql

我有一个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?

2 个答案:

答案 0 :(得分:2)

根据我的经验,哄骗linq生成你想要的SQL是最好的麻烦。如果你有一个比linq更好的查询实现(正常工作并且运行良好),请继续使用它,即使只针对这一个查询。

最快的方式可能是DataContext.ExecuteQuery<TResult>。它甚至会为你返回水合并处理返回的对象,就像linq生成查询本身一样。

http://msdn.microsoft.com/en-us/library/bb361109.aspx

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

http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx

答案 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)

由于我不知道你的对象,你甚至可以删除强制转换(双?)和默认(??)运算符