LinqToSql Создание различных запросов Sql на разных машинах для идентичного кода
У меня есть сайт, созданный с использованием Asp.net и LinqToSql для доступа к данным. В определенном разделе сайта LinqToSql создает запрос, который выглядит следующим образом (с моего компьютера разработчика):
select ...
from table1
left outer join table2 on table1 where ...
left outer join table3 on table2 where ...
Поскольку связь между таблицей 2 и таблицей 1 не всегда существует, в этой ситуации уместно левое внешнее соединение. А поскольку связь между таблицей 3 и таблицей 1 проходит через таблицу 2, ей также необходимо левое внешнее соединение. Этот sql возвращает правильный набор записей.
Я просто поместил код на сервер. При выполнении идентичного кода в том же сценарии LinqToSql создает следующий запрос:
select ...
from table1
left outer join table2 on table1 where ...
join table3 on table2 where ...
По какой-то причине он отображает соединение между table2 и table3 как внутреннее соединение, а не как внешнее соединение. Это приводит к тому, что из запроса возвращается ноль записей.
И компьютер, и разработчик используют.Net 3.5 SP1. Компьютер разработчика - Vista64, Сервер - Windows Server 2003 SP2. Мой коллега, использующий Windows XP PRO, также подтвердил то же правильное поведение на своем компьютере разработчика.
Может кто-нибудь придумать причину, почему сервер будет создавать разные sql? Как я могу это исправить? Кажется, что-то связано с тем, как Linq и.Net работают на сервере. Однако я не могу придумать способ подтвердить и исправить это.
Linq Code (я включаю только те части, которые относятся к разделу, где изменен SQL):
from Import_Table t in db.Import_Tables
select new {
CheckedOutUser = (!t.IsCheckedOut) ? "--" : t.Import_CheckoutHistory.System_User.FirstName + " " + t.Import_CheckoutHistory.System_User.LastName,
CheckedOutUserID = (!t.IsCheckedOut) ? 0 : t.Import_CheckoutHistory.System_UserID};
В контексте приведенного выше описания table1 = Import_Table, table2 = Import_CheckoutHistory, table3 = System_User. Если я закомментирую здесь строку, которая начинается с "CheckedOutUser = ...", то она работает на сервере - так что это определенно виновник.
Фактический sql вернулся:
SELECT
(CASE WHEN NOT ([t0].[IsCheckedOut] = 1) THEN CONVERT(NVarChar(401),'--') ELSE ([t2].[FirstName] + ' ') + [t2].[LastName] END) AS [CheckedOutUser],
(CASE WHEN NOT ([t0].[IsCheckedOut] = 1) THEN 0 ELSE [t1].[system_UserID] END) AS [CheckedOutUserID]
FROM [dbo].[import_Table] AS [t0]
LEFT OUTER JOIN [dbo].[import_CheckoutHistory] AS [t1] ON [t1].[import_CheckoutHistoryID] = [t0].[import_CheckoutHistoryID]
LEFT OUTER/INNER JOIN [dbo].[system_User] AS [t2] ON [t2].[system_UserID] = [t1].[system_UserID]
На машинах разработчиков последняя строка начинается с "Left external". На сервере последняя строка начинается с "Inner"
Обновление: мое решение ниже
3 ответа
Я проверил следующее:
- Оба используют одну и ту же базу данных
- Оба имеют одинаковый код
- Оба имеют одинаковый DBL-файл
Я знаю, что что-то должно быть где-то не синхронизировано, но я не могу найти это.
Поэтому я применил следующий обходной путь: я добавил в свою базу данных представление, которое включает в себя оба левых внешних соединения. Теперь это представление находится в моем файле dbml, и в приведенном выше запросе я ссылаюсь на представление вместо таблицы. Это работает нормально.
Отличается ли ваша производственная база данных от вашей разработки, например, SQL Server 2008 вместо 2005? Я считаю, что LINQ to SQL будет варьировать SQL, который он генерирует, в зависимости от фактической базы данных времени выполнения, с которой он разговаривает.
Кроме того, схемы одинаковы в обеих базах данных?
Похоже, классы LINQ to SQL (DBML и / или связанная генерация кода) между ними не одинаковы - в частности, как определяется связь между этими двумя таблицами.