Linq 的静态函数“Contain”嵌套查询中的内容是否混乱?

发布于 2024-10-20 22:39:49 字数 3546 浏览 1 评论 0原文

我试图减少数据库查询的数量,并在此过程中尝试一次性检索一系列分层实体(之前以递归方式获取)。

我有一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

古镇旧梦 2024-10-27 22:39:49

好的,我发现了问题,实际上它在运行代码时没有发生,但仅在调试模式下发生,具体来说,它似乎是 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!

回忆追雨的时光 2024-10-27 22:39:49

尝试制作 Labels 的副本并在查询的第二部分(联合)中使用它。 EG:

string[] LabelsCopy = new string[5];
Labels.CopyTo(LabelsCopy, 0);

然后在查询后设置断点并检查每个数组的内容(或使用 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:

string[] LabelsCopy = new string[5];
Labels.CopyTo(LabelsCopy, 0);

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 of Labels, but if it is then you'll have proof.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文