具有常量值和投影的联合(或连接等..)

发布于 2024-09-14 07:41:29 字数 898 浏览 3 评论 0原文

我发现 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”是在查询之后插入到投影中的

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

我想我正在寻找一种强制 L2S 将列包含在 SQL 中的方法。更新

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

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

I've discovered a very nasty gotcha with Linq-to-sql, and i'm not sure what the best solution is.

If you take a simple L2S Union statement, and include L2S code in one side, and constants in the other, then the constants do not get included in the SQL Union and are only projected into the output after the SQL, resulting in SQL errors about the number of columns not mathching for the union.

As an example:

(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})

This will generate an error "All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.

This is particularly insidious (and maddening) because there are obviously the same number of expressions in the list, but when you look at the SQL, you will notice that it does not generate a column for "First" in the second half of the Union. This is because "First" is inserted into the projection AFTER the query.

Ok, the easy solution is to just convert each part into Enumerables or Lists or something and then do the union in memory rather than SQL, and that's fine if you're dealing with a small amount of data. However, if you're working with a large set of data, which you then plan to further filter (in sql) before returning it this is not ideal.

I guess what i'm looking for is a way to force L2S to include the column in the SQL. Is that possible?

UPDATE:

While not an exact duplicate, this error is similar to This Question and has similar solutions. So i'm closing, but not deleting this question because it may help someone else come to posible solutions from a different way.

Unfortunately, L2S is too smart of it's own good sometimes.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(2

被你宠の有点坏 2024-09-21 07:41:29

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

I've decided that the only real solution is to use a stored proc. Hope this helps.

安穩 2024-09-21 07:41:29

这是 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 都是明智之举。

This is a bug in the Linq2SQL provider.
In LinqPad you can clearly see the 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}) 

Will server side produce something like this:

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]

This will be a problem because the union will name the second column "value" instead of "Roo", which will cause the outer query to fail.

If you, however, switch the order of the two tables

(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}) 

So that the constant assignment within the generated T-SQL comes in the non-first table, then things may work because T-SQL ignores the column names of subsequent tables.

Note: The first table in a union decides both column name and type. So would be smart to get LinqPad anyway.

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