LinqToSql Создание разных запросов Sql на разных машинах для идентичного кода - PullRequest
4 голосов
/ 06 ноября 2008

У меня есть сайт, созданный с использованием 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 (я включаю только те части, которые относятся к разделу, где изменен 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 ]

2 голосов
/ 06 ноября 2008

Отличается ли ваша производственная база данных от базы разработки, например SQL Server 2008 вместо 2005? Я считаю, что LINQ to SQL будет варьировать SQL, который он генерирует, в зависимости от фактической базы данных времени выполнения, с которой он говорит.

Кроме того, схемы одинаковы в обеих базах данных?

0 голосов
/ 09 ноября 2008

Я проверил следующее:

  1. Оба используют одну и ту же базу данных
  2. Оба имеют одинаковый код
  3. Оба имеют одинаковый DBL-файл

Я знаю, что где-то что-то не синхронизировано, но я не могу найти это.

Итак, я реализовал следующий обходной путь: я добавил в свою базу данных представление, которое включает в себя оба левых внешних объединения. Теперь это представление находится в моем файле dbml, и в приведенном выше запросе я ссылаюсь на представление вместо таблицы. Это работает нормально.

0 голосов
/ 06 ноября 2008

Похоже, что классы LINQ to SQL (DBML и / или связанная генерация кода) между ними не одинаковы - в частности, как определяется связь между этими двумя таблицами.

...