Linq的静态函数'Contain'在嵌套查询中搞乱了它的内容?

时间:2011-03-09 15:10:02

标签: c# .net linq tsql

我正在尝试减少数据库查询的数量,并且这样做我试图一次性检索一系列分层实体(以前是递归获取的)。

我有一个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]

2 个答案:

答案 0 :(得分:2)

好的我发现了问题,实际上它在运行代码时没有发生但只是在调试模式下,特别是它似乎是Scott Gu的LINQ to SQL Debug Visualizer

中的错误

这就是为什么我抓到的TSQL没有参数化,@ David B你提出了一个非常好的观点!

我将在Scott Gu的页面上发表评论,指出这个问题。

全部谢谢!

答案 1 :(得分:0)

尝试复制Labels并在查询的第二部分(联盟)中使用它。 EG:

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

然后在查询后设置一个断点并检查每个数组的内容(或用Console.WriteLine(String.Join(',',Labels))打印出两个数组的内容。)

.Contains()极不可能改变Labels的内容,但如果是,那么你就会有证据。