Linq查询返回不正确的结果集

时间:2009-11-17 21:27:31

标签: .net sql-server linq linq-to-sql

我有一个非常复杂的Linq to SQL查询,它从Microsoft SQL Server数据库返回结果集。使用类似于以下语法创建查询:

Dim db as MyDataContext = MyGetDataContextHelper()
Dim qry = From rslt in db.MyView Select ColumnList

If userParam1 IsNot Nothing Then
    qry = qry.Where(lambda for the filter)
End If

etc....

Return qry.ToList()

查询有几个用户指定的过滤器,包括进行地理半径搜索的过滤器。

这是问题所在。我在最后的“ToList”调用中设置了一个中断。当中断命中时,我使用Linq to SQL Debug Visualizer查看生成的SQL语句。我将该复杂的SQL语句复制到SQL Server Management Studio查询窗口中,并对我的数据库执行它以获得我想要的结果集。因此生成的SQL似乎产生了所需的结果。但是,当我执行查询对象的“ToList”方法时,返回的列表具有较少的行和一些不同的行。我也尝试使用DataContext日志属性写入文件,结果相同。该查询在SQL Management Studio中生成正确的结果集,但ToList方法的结果不正确。

怎么会这样?如果生成的SQL只是通过与SQL Server的连接传递,那么它不应该生成我在SQL Server Management Studio中看到的结果集吗?我假设我误解了Linq to SQL机制,即它不仅仅是SQL Server的一个直通。这是对的吗?

修改 根据下面的请求,这里是Linq生成的SQL的简要版本,为简洁起见,删除了大多数结果列。它在SQL Management Studio中生成正确的结果,但返回到我的应用程序的结果是不同的。

SELECT [t3].[Id]
FROM (
    SELECT DISTINCT [t1].[Id]
    FROM (
        SELECT [t0].[Id], [t0].[ItemDate]
        FROM [dbo].[MySearchView] AS [t0]
        ) AS [t1]
    WHERE (EXISTS(
        SELECT NULL AS [EMPTY]
        FROM [dbo].[ZipCoverage] AS [t2]
        WHERE ([t2].[Id] = [t1].[Id]) 
        AND ([t2].[Latitude] >= (41.09046 - (0.5))) 
        AND ([t2].[Latitude] <= (41.09046 + (0.5))) 
        AND ([t2].[Longitude] >= (-73.43106 - (0.5))) 
        AND ([t2].[Longitude] <= (-73.43106 + (0.5))) 
        AND (ABS(3956.08833132861 * 2 * ATN2(SQRT(POWER(SIN((((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) - 0.717163818159029) / (CONVERT(Float,2))), 2) + (COS(0.717163818159029) * COS((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) * POWER(SIN((((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Longitude]) - -1.28161377022951) / (CONVERT(Float,2))), 2))), SQRT((1 - POWER(SIN((((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) - 0.717163818159029) / (CONVERT(Float,2))), 2)) + (COS(0.717163818159029) * COS((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) * POWER(SIN(((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Longitude]) / (CONVERT(Float,2))), 2))))) <= 5))) 
        AND ([t1].[ItemDate] <= '11/17/2009 8:12:42 PM')
    ) AS [t3]

更新 2009-11-17能否就此问题与MS联系。创建了一个示例应用程序,我将其提交给他们的支持代表。他们重复了这个问题,正在研究中。当我收到回复时会发布回复。

更新 2009-12-21最后在微软的帮助下得到了正确答案。请参阅下面我接受的答案以获得解释。

7 个答案:

答案 0 :(得分:2)

好吧,经过一些来自微软的非常有用的支持代表的来回,我们终于找到了问题的根源。不幸的是,我没有在我原来的帖子中提供足够的信息给任何人在这里做出决定,所以我在这方面道歉。

这是问题 - 作为构造有问题的LINQ查询的代码的一部分,我声明了一个.Net变量:

Dim RadCvtFactor As Decimal = Math.PI / 180

事实证明,当这被传递给SQL时,参数声明(如LINQ日志文件中所证明的)是DECIMAL(29,4)。由于声明中的比例值,无效值会传递给RDBMS,从而导致查询结果出现奇怪的差异。

将.Net变量声明为Single值,如下所示:

Dim RadCvtFactor As Single = Math.PI / 180

完全纠正了问题。

Microsoft代表承认此参数转换可能是“潜在问题”,并会咨询产品团队。

感谢所有提交答案的人。

答案 1 :(得分:1)

立即想到的一件事是许可问题。程序和手动执行的查询是否可能在不同的凭据下运行,因此对数据库具有不同的访问级别?这可能会影响查询的结果。

答案 2 :(得分:1)

我首先看一下你的DataContext。如果没有从SQL Server更新DataContext,那么您可能会返回该表的旧版本。

DataContext在创建数据库时维护数据库的状态。您希望为每组操作使用新的上下文。

答案 3 :(得分:1)

另一种可能性是隔离级别和数据的性质。你在Linq下使用REPEATABLE READ或READ UNCOMMITTED或SNAPSHOT吗?使用SSMS时怎么样?显然,如果数据正在移动,那么松散的隔离级别将允许您跳过行,读取一些行两次,查看行的旧版本等。

另外,您能否更好地了解“非常复杂的查询”是什么样的?您不必使用真实的表名。

答案 4 :(得分:1)

您可以使用DebuggerWriter来检查发送到服务器的实际SQL。

答案 5 :(得分:1)

qry.ToList()

此语句创建并返回所需的列表。如果要稍后使用该列表,则需要将结果分配给某些内容(例如局部变量)。

编辑:感谢您的更新。

我怀疑一定有些东西你没有告诉我们这也可能是一个问题,它可能会存在于此:

Dim db as MyDataContext = MyGetDataContextHelper()

当您使用sql studio时,此方法是否连接到与您连接的数据库相同的数据库?

  • 检查datacontext的Connection属性。
  • 通过使用sql profiler观察它,确保向数据库发出查询。
  • 发出一个非常简单的查询并确认它返回正确的结果。

答案 6 :(得分:1)

这可能听起来很傻,但总是一个好的检查,你是否连接到SSMS中与你的应用程序相同的数据库环境? :)