具有常数值和投影的Union(或Concat等)

时间:2010-08-12 02:22:40

标签: linq-to-sql constants unions

我发现Linq-to-sql非常讨厌,我不确定最佳解决方案是什么。

如果您使用简单的L2S Union语句,并在一侧包含L2S代码,在另一侧包含常量,则常量不会包含在SQL联合中,并且仅在SQL之后投影到输出中,从而导致关于不为union进行数学计算的列数的SQL错误。

举个例子:

(from d in dc.mytable where foo == "bar" select new {First = d.Foo, Second = d.Roo})
.Union(from e in dc.mytable where foo == "roo" select new {First= "", Second = e.Roo})

这将生成错误“使用UNION,INTERSECT或EXCEPT运算符组合的所有查询必须在其目标列表中具有相同数量的表达式。

这特别阴险(并且令人抓狂),因为列表中的表达式数量明显相同,但是当您查看SQL时,您会注意到它在下半年没有为“First”生成列联盟这是因为在查询之后将“First”插入到投影中。

好的,简单的解决方案是将每个部分转换为Enumerables或Lists等,然后在内存而不是SQL中进行联合,如果您处理的是少量数据,那就没问题。但是,如果您正在使用大量数据,然后计划在返回之前进一步过滤(在sql中),这不是理想的。

我想我正在寻找的是一种强制L2S在SQL中包含该列的方法。这可能吗?

更新:

虽然不完全相同,但此错误与This Question类似,并且具有类似的解决方案。所以我结束了,但没有删除这个问题,因为它可能会帮助其他人从不同的方式找到可行的解决方案。

不幸的是,L2S太聪明了,有时它本身也不错。

2 个答案:

答案 0 :(得分:1)

我已经确定唯一真正的解决方案是使用存储过程。希望这会有所帮助。

答案 1 :(得分:1)

这是Linq2SQL提供程序中的一个错误。 在LinqPad中你可以清楚地看到这个bug。

(from d in dc.mytable where foo == "bar" select new {First = d.Foo, Second = d.Roo})  
.Union(from e in dc.mytable where foo == "roo" select new {First= "", Second = e.Roo}) 

服务器端会产生这样的东西:

SELECT [t2].[Foo], [t2].[Roo]
FROM (
    SELECT [t0].[Foo], @p0 AS [value]
    FROM [dc].[Mytable] AS [t0]
    UNION ALL
    SELECT [t1].[Foo], [t1].[Roo]
    FROM [dc].[Mytable] AS [t1]
    ) AS [t2]

这将是一个问题,因为联合会将第二列命名为“value”而不是“Roo”,这将导致外部查询失败。

但是,如果您切换两个表的顺序

(from e in dc.mytable where foo == "roo" select new {First= "", Second = e.Roo})  
.Union(from d in dc.mytable where foo == "bar" select new {First = d.Foo, Second = d.Roo}) 

为了使生成的T-SQL中的常量赋值出现在非第一个表中,那么事情可能会起作用,因为T-SQL会忽略后续表的列名。

注意:union中的第一个表同时决定列名和类型。所以无论如何都要聪明地获得LinqPad。