有人可以帮我解决这个例外吗?我不明白它意味着什么或如何解决它...这是一个SqlException,其中包含以下消息:
使用UNION,INTERSECT或EXCEPT运算符组合的所有查询在其目标列表中必须具有相同数量的表达式。
我在伪代码中运行查询时得到它:
// Some filtering of data
var query = data.Subjects
.Where(has value)
.Where(has other value among some set of values);
// More filtering, where I need to have two different options
var a = query
.Where(some foreign key is null);
var b = query
.Where(some foreign key is not null)
.Where(and that foreign key has a property which is what I want);
query = a.Union(b);
// Final filter and then get result as a list
var list = query
.Where(last requirement)
.ToList();
如果删除a.Union(b)
部分,它会毫无例外地运行。所以我知道错误就在那里。但为什么我会得到它?我该如何解决?我在这里做的事太疯狂吗?我误解了如何使用Union
这个东西吗?
基本上我拥有的是一些拥有其他实体的外键的实体。我需要获得将该外键设置为null
的所有实体或该外来实体满足某些要求的所有实体。
答案 0 :(得分:9)
从您列出的SQL错误判断,您可能遇到了同样的问题。基本上,当Linq to SQL查询在两个不同的查询中使用Concat或Union扩展方法时,Linq to SQL中存在一个错误,它会单独优化每个投影,而不考虑投影必须保持不变才能完成的事实SQL联盟。
参考文献:
LINQ to SQL produces incorrect TSQL when using UNION or CONCAT
Linq to SQL Union Same Fieldname generating Error
如果这恰好是您的问题,我找到了一个适合我的解决方案,如下所示。
var queryA =
from a in context.TableA
select new
{
id,
name,
onlyInTableA,
}
var queryB =
from b in context.TableB
let onlyInTableA = default(string)
select new
{
id,
name,
onlyInTableA,
}
var results = queryA.Union(queryB).ToList();
答案 1 :(得分:4)
由于这看起来像生成的SQL有问题,您应该尝试使用SQL事件探查器,或使用this code for DebuggerWritter class将SQL写入Visual Studio中的输出窗口。
SQL错误通常是由为UNION检索的字段对于2个查询不同引起的。例如,如果第一个查询可能有3个字段,但第二个查询有4个字段,则会发生此错误。因此,在这种情况下,查看生成的SQL肯定会有所帮助。
答案 2 :(得分:0)
你可以在一个查询中写一下吗?
.Where(row => row.ForeignKey == null || row.ForeignKey.SomeCondition);
还有一些合并表达式的方法(OrElse
),但这并非易事。
不确定错误来自哪里!
编辑:尚未测试过,但这在逻辑上应该等同于UNION:
public static IQueryable<T> WhereAnyOf<T>(
this IQueryable<T> source,
params Expression<Func<T, bool>>[] predicates)
{
if (source == null) throw new ArgumentNullException("source");
if (predicates == null) throw new ArgumentNullException("predicates");
if (predicates.Length == 0) return source.Where(row => false);
if (predicates.Length == 1) return source.Where(predicates[0]);
var param = Expression.Parameter(typeof(T), "row");
Expression body = Expression.Invoke(predicates[0], param);
for (int i = 1; i < predicates.Length; i++)
{
body = Expression.OrElse(body,
Expression.Invoke(predicates[i], param));
}
return source.Where(Expression.Lambda<Func<T, bool>>(body, param));
}
答案 3 :(得分:0)
query = a.Union(b);
改变捕获的变量不是一个好主意......可能是错误的原因。
更新:确定不是
这是另一个想法。提示位于错误消息中。
var a = query
.Where(some foreign key is null)
.Select(x => x);
或者通过添加另一个“假”来玩,直到它们变得平等:)
答案 4 :(得分:0)
我会调用data.GetCommand(query)
并分析生成的DbCommand
(尤其是生成的SQL字符串)。这应该可以为你找出问题提供线索。
任何地方都没有投影,所以我希望两个目标列表都是一样的。
您可以尝试将查询减少到仍然无效的较小查询。从query.Union(query)
开始(这应该至少有效)。然后逐个添加Where
个来电,看看它何时停止工作。
必须是您的Where
次调用之一,这会为您的选择列表添加额外的列。
答案 5 :(得分:0)
您是否有机会将值传递给变量中的“选择”侧,或者您是否多次返回相同的字段? SP1引入了一个错误,它试图“优化”这些东西,并且可能导致联合查询中断(由于查询部分'优化'不同的传入参数)。
如果您发布实际查询而不是伪代码,则可以更容易地识别是否是这种情况。
(如果是这种情况,则解决方法是首先实现各个部分,然后进行客户端(L2O)联合)。
答案 6 :(得分:0)
jpierson正确地总结了问题
我也有问题,这次是由select语句中的一些文字引起的:
Dim results = (From t in TestDataContext.Table1 _
Where t.ID = WantedID _
Select t.name, SpecialField = 0, AnotherSpecialField = 0, t.Address).Union _
From t in TestDataContext.Table1 _
Where t.SecondID = WantedSecondID _
Select t.name, SpecialField = 1, AnotherSpecialField = 0, t.Address)
优化了“SpecialField = 0”和“AnotherSpecialField = 0”的第一个子查询,导致在联合中使用一个字段而不是两个字段,这显然会失败。
我不得不改变第一个查询,以便特殊字段和AnotherSpecialField具有不同的值,与第二个子查询非常相似。
答案 7 :(得分:0)
我有这个问题。使用Sql 08我有两个表函数,在两种情况下都返回一个int和一个字符串。我创建了一个复杂的对象并使用linq来尝试UNION。有一个IEqualityComparer来做比较。所有编译都很好,但在不受支持的重载下崩溃了。好吧,我意识到所讨论的问题似乎与推迟执行有关。所以我得到了集合,并放置ToList(),然后做UNION,这一切都很好。不确定这是否有用,但它适用于我