LINQ 和 SQL 中看似等效的查询返回不同的结果 [重复]

Posted

技术标签:

【中文标题】LINQ 和 SQL 中看似等效的查询返回不同的结果 [重复]【英文标题】:Seemingly equivalent queries in LINQ and SQL returns different results [duplicate] 【发布时间】:2016-02-08 13:48:04 【问题描述】:

不知道为什么它被链接为骗子。问题大不相同。答案是不同的。不确定要改变什么。如果有人看到我遗漏的东西,请告诉我...

使用这两个查询我得到了不同数量的结果。在分析了几个小时之后,我需要认输,承认我无法发现显着性差异。由于我的方法库已清空,我正在寻求帮助。

LINQ

List<Uno> result = context.Unos
  .Join(context.Duos, uno => uno.CommonId, duo => duo.CommonId,
    (uno, duo) => new  Uno = uno, Duo = duo )
  .Where(item => item.Uno.Amount > 0
    && item.Duo.Type == 2)
  .Select(item => item.Uno)
  .ToList();

SQL

select * from Uno as u
join Duo as d on d.CommonId = u.CommonId
where u.Amount > 0
  and d.Type = 2

第一个问题是上述两个陈述是否确实是等价的,或者我是否遗漏了什么。第二个问题是我缺少什么(如果有的话)或如何解决它(如果我没有)。

    调用同一个数据库。 结果的数量相差很大(142 和 1437)。 为内部连接提取相同的结果集。 UnoDuo 都是视图,而不是表格。

我还能验证什么?

编辑

在社区的大力支持下,我们确定 LINQ 查询可以通过以下命令进行 SQL 化。

var wtd = context.Unos
  .Join(context.Duos, uno => uno.CommonId, duo => duo.CommonId,
    (uno, duo) => new  Uno = uno, Duo = duo )
  .Where(item => item.Uno.Amount > 0
    && item.Duo.Type == 2)
  .Select(item => item.Uno)
  .ToString();

疯狂的是,在 SQL 管理器中执行 that 字符串会产生 142 个结果(就像上面示例中的查询,SQL 版本一样),并且它与它的差异很小。但是,执行 LINQ 查询本身会产生 1437 个结果。我太糊涂了,连哭都哭不出来……

"SELECT \r\n [Extent1].[CommonId] AS [CommonId],\r\n [Extent1].[X] AS [X]\r\n FROM (SELECT \n [Uno].[ CommonId] AS [CommonId], \n [Uno].[X] AS [X]\n FROM [Finance].[Uno] AS [Uno]) AS [Extent1]\r\n INNER JOIN (SELECT \n [ Duo].[CommonId] AS [CommonId],\n [Duo].[Y] AS [Y],\n [Duo].[Z] AS [Z],\n [Duo].[Type] AS [类型],\n [Duo].[U] AS [U],\n [Duo].[V] AS [V]\n FROM [Finance].[Duo] AS [Duo]) AS [Extent2] ON [Extent1].[CommonId] = [Extent2].[CommonId]\r\n WHERE ([Extent1].[X] > cast(0 as decimal(18))) AND ([Extent2].[Type] = @ p__linq__0)"

【问题讨论】:

'and d.Type = 2' 是错字吗?他两个来源的行数是多少?哪个结果是正确的? @TaW 打错字了?远不是我能看到的。我错过了什么吗?类型是一个始终为 2 的整数(对于此操作)。它在 Duo 表中。 @TaW 行数分别为 142 和 1437(参见 #2)。我不确定哪个是正确的,但我猜是 SQL 版本。一个给出较少数量的结果。此外,它不是表格而是视图,如果这很重要的话。 @KonradViltersten 你试过这个var query = ..... 除了ToList 之外的所有东西。然后var sql = query.ToString(); 并使用 Text Visualizer 打开 嗯,ToString(),真的吗???您是否查看了大结果集并检查它是否包含空位置?这些可能会导致这些项目被 both SQL 根据左内连接 的定义排除在字符串之外。 【参考方案1】:

这是在实体框架中映射视图时经常发生的事情。与常规数据库表不同,视图通常没有明确的唯一键值。当 EF 遇到具有相同主键值的行时,它只会复制属于它已经知道的键的行。在连接中,这可能会导致 EF 产生更多的子记录,因为这个已知的第一个行可能比真实的数据库行有更多的子记录。

解决方法是确保视图具有唯一标识行的字段(或字段组合)。当然,在 EF 中,这应该映射为(可能是复合的)主键。

我不知道为什么 EF 会显示这种行为。我认为它应该有可能抛出一个它实现重复实体的异常。这个“特性”总是会引起很多混乱。

【讨论】:

【参考方案2】:

这是一个长镜头,但这个 LINQ 表达式会改变什么吗?

(from uno in context.Unos
 join duo in context.Duos on uno.CommonId equals duo.CommonId
 where uno.Amount > 0 && duo.Type == 2
 select new Uno = uno, Duo = duo
).ToList()

我更喜欢这种形式,因为它看起来像真正的 SQL 请求。不知何故,你的 LINQ 中的 Join 语句让我很困扰......

【讨论】:

与麻烦的 LINQ 中的结果相同。但是,我会给你 +1,因为你只是进一步推动了这个问题。我们现在知道,上面的表达式(SQLish 形式)仍然比它的 SQL 对应物产生更多的结果。 谢谢 :) 这个问题让我想起了我第一次使用 SQL 和 Join 关键字导致一长串重复行...也许 Distinct 可能会有所帮助! 不行,不行。我尝试使结果集不同 - 返回相同的计数。该死的,不能确定这些事情真是令人沮丧……我已经和我的老板谈过了,我们只是将 SQL 查询作为字符串执行,但是,尽管从实用上讲已经足够了,但这根本不是一个好的解决方案。感觉就像向那台愚蠢的蹩脚电脑屈服了,呵呵。 实际上它可能是更好的解决方案,因为它可以让 DBMS 完成它的工作并最小化网络流量。但我理解你的沮丧。也许如果你喃喃自语'jonskeetjonskeetjonskeet'..?【参考方案3】:

尝试查看您在调试此位置时在 IntelliTrace 窗口中执行 LINQ 后运行的查询。然后与您的SQL进行比较,我认为它们是不同的。如果您没有 IntelliTrace,请尝试 Express Profiler。只需设置 SQL Server 的名称,单击 Trace 并监视它。我希望它会有所帮助!

【讨论】:

叹息...猜猜谁没有执行跟踪的权限...我会尝试在服务器上授予我一个,但可能我不能。无论如何努力+1,如果我设法获得许可,我会回复你。 当然,执行我用来登录的grant alter trace to NServiceBus,会产生一个错误,说我不能。似乎我已经有了这些......我在探查器的服务器文本框中究竟输入了什么?我输入了 10.100.128.35,这是服务器的 IP,但也许我需要输入更多内容? 好吧,我以为你是在本地环境下开发的。下一个变体,调用 ToTraceString() 而不是 ToList() 并将返回值更改为 var。调试它,在结果变量中你会得到查询文本。 根据智能感知,我没有 ToTraceString()。我试着把它放在那里 ToList 现在。没有运气... 我从某人那里得到了一个提示,并得到了查询执行的 SQL。真的很奇怪 - 查看原始帖子中的最新 cmets。

以上是关于LINQ 和 SQL 中看似等效的查询返回不同的结果 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

linq 等效于通用函数的'select *' sql?

用于LINQ的SQL等效扩展方法并不明显

SQL Server STRING_AGG() :在 Linq 中等效

具有 unnest 的 PostgreSQL 查询不返回空值的结果行

将OData Uri转换为他的等效Linq表达式

linq查询执行时返回对应的sql