Подтвердить что ты не робот

Сделать Linq для Sql генерировать T-SQL с ISNULL вместо COALESCE

У меня есть запрос linq to sql, который возвращает некоторые заказы с ненулевым балансом (на самом деле запрос немного сложнее, но для простоты я пропустил некоторые подробности). Этот запрос также должен возвращать заказы без CardItems (оба подзапроса возвращают NULL в T-SQL, а сравнение двух 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 в этой ситуации?

4b9b3361

Ответ 1

По моему опыту, уловка 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

Ответ 2

Поскольку вы принимаете строку без суммы, которая должна быть суммирована как ноль, вы можете просто отфильтровать строки без суммы и не беспокоиться об 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?) и операторы по умолчанию (??)