SubSonic 2.2 SqlQuery объект генерирует очень разные SQL для оператора WHERE ... IN для SQL Server 2008 и SQL Server 2005 - PullRequest
2 голосов
/ 11 ноября 2009

Кто-нибудь имеет представление, почему объект SubSonic 2.2 SubSonic.SqlQuery будет генерировать очень разные sql для одного и того же кода C # при работе с SQL Server 2005 или SQL Server 2008?

У меня есть сайт, который некоторое время работал на SubSonic 2.2 / SQL Server 2005. Я только что обновил БД до mssql 2008 и столкнулся со следующей ошибкой:

SqlException (0x80131904): неверный синтаксис рядом с ключевым словом 'AND'

Я сбросил SqlQuery.ToString () в точке сбоя и заметил следующие различия между выполнением одной и той же кодовой базы в SQL Server 2005 и SQL Server 2008. Вот исходный код:

SubSonic.SqlQuery q = new Select()
  .From(Views.VwSearchIndexQuery2Mtx)
  .Paged(pageNumber, maximumRows)
  .Where(VwSearchIndexQuery2Mtx.Columns.SearchIndexQueryId)
    .In(
        new Select(SearchIndexQueryGroupMap.Columns.SearchIndexQueryId)
          .From(Tables.SearchIndexQueryGroupMap)
          .Where(SearchIndexQueryGroupMap.Columns.SearchIndexQueryGroupId)
          .IsEqualTo(searchIndexQueryGroupId));

И автоматически сгенерированный sql для SQL Server 2005:

 SELECT * FROM     
(SELECT ROW_NUMBER() OVER ( ORDER BY CreatedOn DESC ) AS Row
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryId]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryName]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchTerms]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexId]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexName]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[IndustryId]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[IndustryName]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[DaysMonitored]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[Incidents]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[Relevance]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[CreatedOn]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[CreatedBy]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[ModifiedOn]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[ModifiedBy]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[Deleted]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryTypeId]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryTypeName]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[LastUpdatedTime]     
FROM [dbo].[Vw_SearchIndexQuery2_Mtx]    
WHERE [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryId] 
IN (SELECT [dbo].[SearchIndexQueryGroup_Map].[SearchIndexQueryId]  
FROM [dbo].[SearchIndexQueryGroup_Map]  
WHERE [dbo].[SearchIndexQueryGroup_Map].[SearchIndexQueryGroupId] =   @SearchIndexQueryGroupId0 )  )             
AS PagedResults WHERE  Row >= 1 AND Row <= 20

Автоматически сгенерированный sql для SQL Server 2008:

DECLARE @Page int      
DECLARE @PageSize int       
SET @Page = 1      
SET @PageSize = 20       
SET NOCOUNT ON       
-- create a temp table to hold order ids      
DECLARE @TempTable TABLE (IndexId int identity, _keyID Int)       
-- insert the table ids and row numbers into the memory table      
INSERT INTO @TempTable      (        _keyID      )      
SELECT        [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryId]           
 FROM [dbo].[Vw_SearchIndexQuery2_Mtx]  
 WHERE [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryId] 
 IN (SELECT [dbo].[SearchIndexQueryGroup_Map].[SearchIndexQueryId]  
  FROM [dbo].[SearchIndexQueryGroup_Map]  
  WHERE [dbo].[SearchIndexQueryGroup_Map].[SearchIndexQueryGroupId] 
                         = @SearchIndexQueryGroupId0 
    ) 
   /* it's at this next AND where the error is thrown */
 AND [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryId] 
 IN (SELECT [dbo].[SearchIndexQueryGroup_Map].[SearchIndexQueryId]  
  FROM [dbo].[SearchIndexQueryGroup_Map]  
  AND [dbo].[SearchIndexQueryGroup_Map].[SearchIndexQueryGroupId] 
                         = @SearchIndexQueryGroupId0 
                  )  
ORDER BY CreatedOn DESC       
-- select only those rows belonging to the proper page          
SELECT [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryId]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryName]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchTerms]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexId]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexName]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[IndustryId]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[IndustryName]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[DaysMonitored]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[Incidents]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[Relevance]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[CreatedOn]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[CreatedBy]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[ModifiedOn]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[ModifiedBy]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[Deleted]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryTypeId]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryTypeName]
, [dbo].[Vw_SearchIndexQuery2_Mtx].[LastUpdatedTime]   
FROM [dbo].[Vw_SearchIndexQuery2_Mtx]       
INNER JOIN @TempTable t ON [dbo].[Vw_SearchIndexQuery2_Mtx].[SearchIndexQueryId] =    t._keyID      
WHERE t.IndexId BETWEEN ((@Page - 1) * @PageSize + 1) AND (@Page * @PageSize)

Я знаю, почему происходит ошибка - sql недействителен из-за того, что я прокомментировал выше. Я просто не могу понять, почему SubSonic генерирует недопустимый SQL после того, как он работал на SQL Server 2008. Вы увидите, что для SQL Server 2008 он использует временную таблицу и, похоже, повторяет подпрограмму WHERE ... IN. запрос. Я подумал, что, возможно, это был уровень совместимости ISO, так как для обновленной БД было установлено значение 100. Поэтому я протестировал, установив его на 90 и 80, и SubSonic генерирует тот же sql, что и в каждом случае. (И, кстати, код, сгенерированный для SQL Server 2005, который использует «select rownumber () over ... as row», прекрасно работает с SQL Server 2008.)

У кого-нибудь есть идеи, почему это происходит и как его отследить?

Большое спасибо,

Терри

Ответы [ 3 ]

2 голосов
/ 12 ноября 2009

Возможно, это уже исправлено в источнике? Я предлагаю вам попробовать самый последний источник из github , чтобы увидеть, была ли решена проблема.

По сути, как вы и сказали, генератор 2005 года переопределяет метод BuildPagedSelectStatement (), предоставляемый ANSISqlGenerator. Генератор 2008 наследует от 2005 года, поэтому должен использовать тот же метод подкачки, что и 2005.

Это можно увидеть, сравнив эти два файла :

Полагаю, вы также увидите поведение, которое вы описываете в базе данных SQL 2000, поскольку оно не переопределяет метод ANSISqlGenerator.BuildPagedSelectStatement ().

Кроме того, Я не думаю, что уровень совместимости используется для определения генератора SQL:

    public static bool IsSql2008(DataProvider provider)
    {
        return provider.DatabaseVersion.IndexOf("2008 - 10.") > -1 ||
        provider.DatabaseVersion.IndexOf("2008 (RTM) - 10.") > -1;
    }

И, учитывая, что ANSI-генератор используется в действительности, проблема с AND может быть вызвана этой строкой в ​​BuildPagedSqlStatement ():

    //have to doctor the wheres, since we're using a WHERE in the paging
    //bits. So change all "WHERE" to "AND"
    string tweakedWheres = wheres.Replace("WHERE", "AND");

Это должно быть немного умнее, хотя вопрос, который вы затронули в отношении дублированного предложения, также должен быть рассмотрен.

1 голос
/ 17 сентября 2010

Эта проблема задокументирована здесь . Я только что разобрал и передал исправление, поэтому оно должно быть включено в ближайшее время.

1 голос
/ 28 апреля 2010

Только что столкнулся с этой ошибкой и очень рад, что нашел эту страницу, потому что я понятия не имел, почему это происходит.

Кажется, что запуск SQL Server 2008 SP1 приводит к тому, что IsSql2008 становится ЛОЖНЫМ. Поскольку возвращаемое значение DatabaseVersion (на моем компьютере) возвращается как «Microsoft SQL Server 2008 (SP1) - 10.0.2531.0 (X64) ...», что не соответствует критериям функции IsSql2008.

Похоже, это все еще не решено в кодовой базе github?

Почему бы не сделать что-нибудь попроще, например,

if (provider.DatabaseVersion.Contains("SQL Server 2008"))
...