我发现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太聪明了,有时它本身也不错。
答案 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。