3

我发现 Linq-to-sql 有一个非常讨厌的问题,我不确定最好的解决方案是什么。

如果采用简单的 L2S Union 语句,一侧包含 L2S 代码,另一侧包含常量,则常量不会包含在 SQL Union 中,只会投影到 SQL 之后的输出中,从而导致 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 时,您会注意到它并没有为 Union 的后半部分生成“First”列. 这是因为“First”在查询之后被插入到投影中。

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

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

更新:

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

不幸的是,L2S 有时太聪明了。

4

2 回答 2

1

我决定唯一真正的解决方案是使用存储过程。希望这可以帮助。

于 2010-08-29T19:22:45.293 回答
1

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

(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 忽略了后续表的列名。

注意:联合中的第一个表决定了列名和类型。无论如何,获得 LinqPad 会很聪明。

于 2010-11-17T13:59:52.333 回答