2

有谁知道为什么 SubSonic 2.2 SubSonic.SqlQuery 对象在针对 SQL Server 2005 或 SQL Server 2008 运行时会为相同的 C# 代码生成非常不同的 sql?

我有一个站点在 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 Server 2005 自动生成的 sql 是:

 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 Server 2008 自动生成的 sql:

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)

我知道为什么会发生错误-我在上面评论过的 AND 使 sql 无效。我只是无法弄清楚为什么 SubSonic 在 SQL Server 2008 上运行后会生成无效的 SQL。您会看到,对于 SQL Server 2008,它使用了一个临时表,而且看起来它也在重复 WHERE...IN 子询问。我想这可能是 ISO 兼容级别,因为升级后的数据库设置为 100。所以我已经将它设置为 90 和 80 进行了测试,并且 SubSonic 生成与每种情况相同的 sql。(顺便说一句,为 SQL Server 2005 生成的代码使用“select rownumber() over ... as row”对 SQL Server 2008 执行得很好。)

有谁知道为什么会发生这种情况以及如何追踪它?

非常感谢,

特里

4

3 回答 3

2

这可能已经在源代码中修复了?我建议您尝试从github获取最新的资源,看看问题是否已得到解决。

基本上,正如您所说的那样——2005 生成器覆盖了 ANSISqlGenerator 提供的 BuildPagedSelectStatement() 方法。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");

它需要比这更聪明一些,尽管你提出的关于重复条款的观点也需要解决。

于 2009-11-12T01:30:56.030 回答
1

刚刚遇到这个错误,很高兴我找到了这个页面,因为我不知道为什么会这样。

似乎运行 SQL Server 2008 SP1 会导致 IsSql2008 为 FALSE。由于返回的 DatabaseVersion(在我的机器上)返回为“Microsoft SQL Server 2008 (SP1) - 10.0.2531.0 (X64) ...”,这不符合 IsSql2008 函数的标准。

看起来这仍然没有在 github 代码库上得到解决?

为什么不有一些更简单的东西,比如

if (provider.DatabaseVersion.Contains("SQL Server 2008"))
于 2010-04-28T10:14:07.337 回答
1

此处记录了此问题。我刚刚分叉并提交了修复,所以它应该很快就会包含在内。

于 2010-09-17T01:25:45.477 回答