12

我有一个 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运算符,这比完全相同的 T-SQL 查询慢十倍,因为其中的子查询将 COALESCE 替换为ISNULL 。在这种情况下是否有可能生成 ISNULL ?

4

2 回答 2

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

于 2012-07-13T07:40:22.363 回答
0

由于您假设没有金额的行被求和为零,那么您可以过滤掉没有金额的行,而不必担心 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)

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

于 2012-06-08T15:23:34.227 回答