Linq 的静态函数“Contain”嵌套查询中的内容是否混乱?
我试图减少数据库查询的数量,并在此过程中尝试一次性检索一系列分层实体(之前以递归方式获取)。
我有一个 Labels
属性,其中包含一组字符串:
public string[] Labels { get; set; } // new string[] {"{{a}}", "{{b}}", "{{c}}", "{{d}}", "{{e}}"};
我正在使用它来构造第一个查询:
var IDeferredTopLabels=
db.labels
.Where(l =>
l.site_id == this.site_id &&
this.Labels.Contains(l.name_for_code)
)
.Select(l => new LabelWithParentId { Label = l, ParentId = null });
如果在调试时检查上述内容,将生成以下 TSQL
SELECT [t0].[id], [t0].[name_for_code], [t0].[site_id], [t0].[priority_level]
FROM [dbo].[labels] AS [t0]
WHERE ([t0].[site_id] = 15) AND ([t0].[name_for_code] IN ('{{a}}', '{{b}}', '{{c}}', '{{d}}', '{{e}}'))
到目前为止一切顺利,如下在 IDeferredToplabels
声明中,我使用 Union
扩展第一个查询,指定应如何获取子 Label
实体:
var IDeferredWithChildLabels = IDeferredTopLabels
.Union(
db.label__labels
.Where(ll =>
db.labels
.Where(l =>
l.site_id == this.site_id &&
this.Labels.Contains(l.name_for_code)
)
.Select(l => l.id)
.Contains(ll.parent_label_id)
)
.Select(ll => new LabelWithParentId { Label = ll.label1, ParentId = ll.parent_label_id})
);
现在,如果我检查 TSQL 生成是:
SELECT [t4].[id], [t4].[name_for_code], [t4].[site_id], [t4].[priority_level], [t4].[value] AS [ParentId]
FROM (
SELECT [t0].[id], [t0].[name_for_code], [t0].[site_id], [t0].[priority_level], NULL AS [value]
FROM [dbo].[labels] AS [t0]
WHERE ([t0].[site_id] = 15) AND ([t0].[name_for_code] IN ('{{a}}', '{{b}}', '{{c}}', '{{d}}', '{{e}}'))
UNION
SELECT [t2].[id], [t2].[name_for_code], [t2].[site_id], [t2].[priority_level], [t1].[parent_label_id] AS [value]
FROM [dbo].[label__label] AS [t1]
INNER JOIN [dbo].[labels] AS [t2] ON [t2].[id] = [t1].[label_id]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[labels] AS [t3]
WHERE ([t3].[id] = [t1].[parent_label_id]) AND ([t3].[site_id] = 15) AND ([t3].[name_for_code] IN ('{{a}}', '{{b}}', '{{c}}', '{{a}}'0, '{{a}}'1))
)
) AS [t4]
如果您在第二个 TSQL 查询的末尾看到 IN ('{{a}}', '{{b}}', '{{c}}', '{{a} }'0, '{{a}}'1))
,该字符串集在倒数第二个和最后一个元素旁边有一些意想不到的 0 和 1,而且它不再是初始字符串集(即 ' {{a}}'、'{{b}}'、'{{c}}'、'{{d}}'、'{{e}}') 而是 '{{a}} '、'{{b}}'、'{{c}}'、'{{a}}'、'{{a}}'
。
我到底做错了什么!?
我一无所知,感谢您的帮助,谢谢。
编辑:
我只是尝试使用 int[]
并比较 id
而不是 name_for_code
并且我仍然附加 1 和 0数组的最后 2 个元素以及数组元素都是错误的:
SELECT [t4].[id], [t4].[name_for_code], [t4].[site_id], [t4].[priority_level], [t4].[value] AS [ParentId]
FROM (
SELECT [t0].[id], [t0].[name_for_code], [t0].[site_id], [t0].[priority_level], NULL AS [value]
FROM [dbo].[labels] AS [t0]
WHERE ([t0].[site_id] = 15) AND ([t0].[id] IN (1, 2, 3, 4, 5))
UNION
SELECT [t2].[id], [t2].[name_for_code], [t2].[site_id], [t2].[priority_level], [t1].[parent_label_id] AS [value]
FROM [dbo].[label__label] AS [t1]
INNER JOIN [dbo].[labels] AS [t2] ON [t2].[id] = [t1].[label_id]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[labels] AS [t3]
WHERE ([t3].[id] = [t1].[parent_label_id]) AND ([t3].[site_id] = 15) AND ([t3].[id] IN (1, 2, 3, 10, 11))
)
) AS [t4]
I'm trying to reduce the number of database queries and in doing so I'm attempting to retrieve a series of hierarchical entities (that were previously fetched recursively) in one go.
I've got a Labels
property holding a set of strings:
public string[] Labels { get; set; } // new string[] {"{{a}}", "{{b}}", "{{c}}", "{{d}}", "{{e}}"};
that I'm using to construct a first query:
var IDeferredTopLabels=
db.labels
.Where(l =>
l.site_id == this.site_id &&
this.Labels.Contains(l.name_for_code)
)
.Select(l => new LabelWithParentId { Label = l, ParentId = null });
The above, if inspected while debugging, would generate the following TSQL
SELECT [t0].[id], [t0].[name_for_code], [t0].[site_id], [t0].[priority_level]
FROM [dbo].[labels] AS [t0]
WHERE ([t0].[site_id] = 15) AND ([t0].[name_for_code] IN ('{{a}}', '{{b}}', '{{c}}', '{{d}}', '{{e}}'))
So far so good, following the IDeferredToplabels
declaration I'm extending the first query with a Union
specifying how child Label
entities should be fetched:
var IDeferredWithChildLabels = IDeferredTopLabels
.Union(
db.label__labels
.Where(ll =>
db.labels
.Where(l =>
l.site_id == this.site_id &&
this.Labels.Contains(l.name_for_code)
)
.Select(l => l.id)
.Contains(ll.parent_label_id)
)
.Select(ll => new LabelWithParentId { Label = ll.label1, ParentId = ll.parent_label_id})
);
Now if I inspect the TSQL generate is:
SELECT [t4].[id], [t4].[name_for_code], [t4].[site_id], [t4].[priority_level], [t4].[value] AS [ParentId]
FROM (
SELECT [t0].[id], [t0].[name_for_code], [t0].[site_id], [t0].[priority_level], NULL AS [value]
FROM [dbo].[labels] AS [t0]
WHERE ([t0].[site_id] = 15) AND ([t0].[name_for_code] IN ('{{a}}', '{{b}}', '{{c}}', '{{d}}', '{{e}}'))
UNION
SELECT [t2].[id], [t2].[name_for_code], [t2].[site_id], [t2].[priority_level], [t1].[parent_label_id] AS [value]
FROM [dbo].[label__label] AS [t1]
INNER JOIN [dbo].[labels] AS [t2] ON [t2].[id] = [t1].[label_id]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[labels] AS [t3]
WHERE ([t3].[id] = [t1].[parent_label_id]) AND ([t3].[site_id] = 15) AND ([t3].[name_for_code] IN ('{{a}}', '{{b}}', '{{c}}', '{{a}}'0, '{{a}}'1))
)
) AS [t4]
If you see at the end of this second TSQL Query, the part IN ('{{a}}', '{{b}}', '{{c}}', '{{a}}'0, '{{a}}'1))
, the set of strings have some unespected 0 and 1 next to the second last and last element plus it is no longer the initial set of strings (ie '{{a}}', '{{b}}', '{{c}}', '{{d}}', '{{e}}') but instead '{{a}}', '{{b}}', '{{c}}', '{{a}}', '{{a}}'
.
What I'm I doing wrong!?
I'm clueless, I appreciate your help, thank you.
EDIT:
I just tried to use an int[]
and compare the id
rather then the name_for_code
and I'm still getting 1 and 0 appended to the last 2 elements of the array as well as the array elements are wrong:
SELECT [t4].[id], [t4].[name_for_code], [t4].[site_id], [t4].[priority_level], [t4].[value] AS [ParentId]
FROM (
SELECT [t0].[id], [t0].[name_for_code], [t0].[site_id], [t0].[priority_level], NULL AS [value]
FROM [dbo].[labels] AS [t0]
WHERE ([t0].[site_id] = 15) AND ([t0].[id] IN (1, 2, 3, 4, 5))
UNION
SELECT [t2].[id], [t2].[name_for_code], [t2].[site_id], [t2].[priority_level], [t1].[parent_label_id] AS [value]
FROM [dbo].[label__label] AS [t1]
INNER JOIN [dbo].[labels] AS [t2] ON [t2].[id] = [t1].[label_id]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[labels] AS [t3]
WHERE ([t3].[id] = [t1].[parent_label_id]) AND ([t3].[site_id] = 15) AND ([t3].[id] IN (1, 2, 3, 10, 11))
)
) AS [t4]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好的,我发现了问题,实际上它在运行代码时没有发生,但仅在调试模式下发生,具体来说,它似乎是 Scott Gu 的 LINQ to SQL 调试可视化工具
这就是为什么我抓取的 TSQL 没有参数化,@David B 你提出了一个非常好的观点!
我将在 Scott Gu 的页面上发表评论指出这个问题。
谢谢大家!
OK I found the problem and actually it was not happening when running the code but only in debug mode and specifically it seems it is a bug in Scott Gu's LINQ to SQL Debug Visualizer
That is why the TSQL that I was grabbing was not parameterized, @David B you made a very good point!
I will leave a comment on Scott Gu's page pointing to this question.
Thanks all!
尝试制作
Labels
的副本并在查询的第二部分(联合)中使用它。 EG:然后在查询后设置断点并检查每个数组的内容(或使用
Console.WriteLine(String.Join(',',Labels))
打印出两个数组的内容。.Contains()
极不可能更改Labels
的内容,但如果确实如此,那么您就有证据了。Try making a copy of
Labels
and using that in the second part of the query (the Union). EG:Then set a breakpoint after the query and inspect the contents of each array (or print out the contents of both arrays with
Console.WriteLine(String.Join(',',Labels))
).It's extremely unlikely that
.Contains()
is changing the contents ofLabels
, but if it is then you'll have proof.