我有一个非常复杂的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最后在微软的帮助下得到了正确答案。请参阅下面我接受的答案以获得解释。
答案 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时,此方法是否连接到与您连接的数据库相同的数据库?
答案 6 :(得分:1)
这可能听起来很傻,但总是一个好的检查,你是否连接到SSMS中与你的应用程序相同的数据库环境? :)