C# 为什么linqtosql错误地删除了我的union中的字段?
我正在尝试将多个查询聚合在一起,以便使用通用数据结构为我的用户提供最新的更新显示。在我的第一个函数中,我有以下select子句:C# 为什么linqtosql错误地删除了我的union中的字段?,c#,linq-to-sql,.net-3.5,C#,Linq To Sql,.net 3.5,我正在尝试将多个查询聚合在一起,以便使用通用数据结构为我的用户提供最新的更新显示。在我的第一个函数中,我有以下select子句: .Select(x => new PlayerUpdateInfo { FirstName = x.PodOptimizedSearch.FirstName, LastName = x.PodOptimizedSearch.LastName, RecruitId = x.RecruitId, Date = x.Date,
.Select(x => new PlayerUpdateInfo
{
FirstName = x.PodOptimizedSearch.FirstName,
LastName = x.PodOptimizedSearch.LastName,
RecruitId = x.RecruitId,
Date = x.Date,
UpdateMessage = x.IsAddedAction
? "Player was added to this recruiting board by " + x.Person.FirstName
+ " " + x.Person.LastName
: "Player was removed from this recruiting board by " +
x.Person.FirstName + " " + x.Person.LastName,
// Defaults for union support
Team = string.Empty,
UpdateComments = x.Comments,
TeamId = 0,
State = string.Empty
});
调用此函数后,将正确生成一个返回9个字段的查询。第二种方法的选择是:
select new PlayerUpdateInfo
{
FirstName = recruit.FirstName,
LastName = recruit.LastName,
RecruitId = recruit.RecruitId,
Date = asset.CreateDate,
UpdateMessage = "New Full Game Added",
// Defaults for union support
Team = null,
UpdateComments = null,
TeamId = 0,
State = null
};
当此查询自行运行时,它将正确返回9个值。然而,当我试着去做
var query = GetFirstQuery();
query = query.union(GetSecondQuery());
我得到一个sql异常,查询失败,因为所有查询的字段数都不相同。对生成的SQL的研究表明,第一个查询是正确的,但Linq正在生成第二个联合查询,以便只包含7个字段。测试之后,Linq似乎在优化空值,因此它只返回一个空列,而不是3个,从而导致错误匹配
为什么linqtosql错误地生成联合,我如何解决这个问题
编辑:
好的,这个问题似乎涉及到.NET3.5的Linq到Sql中的联合链接。显然,这不会发生在4年内。使用以下代码:
protected IQueryable<PlayerUpdateInfo> Test1()
{
return PodDataContext.Assets
.Select(x => new PlayerUpdateInfo
{
Date = DateTime.Now,
FirstName = x.Title,
LastName = string.Empty,
RecruitId = 0,
State = string.Empty,
Team = string.Empty,
TeamId = 0,
UpdateComments = string.Empty,
UpdateMessage = string.Empty
});
}
protected IQueryable<PlayerUpdateInfo> Test2()
{
return PodDataContext.SportPositions
.Select(x => new PlayerUpdateInfo
{
Date = DateTime.Now,
FirstName = string.Empty,
LastName = x.Abbreviation,
RecruitId = 0,
State = string.Empty,
Team = string.Empty,
TeamId = 0,
UpdateComments = string.Empty,
UpdateMessage = string.Empty
});
}
在.net 4中生成以下代码:
SELECT [t4].[value] AS [RecruitId], [t4].[Title] AS [FirstName], [t4].[value2] AS [LastName], [t4].[value3] AS [Team], [t4].[value4] AS [TeamId], [t4].[value5] AS [State], [t4].[value6] AS [UpdateMessage], [t4].[value7] AS [UpdateComments], [t4].[value8] AS [Date]
FROM (
SELECT [t2].[value], [t2].[Title], [t2].[value2], [t2].[value3], [t2].[value4], [t2].[value5], [t2].[value6], [t2].[value7], [t2].[value8]
FROM (
SELECT @p0 AS [value], [t0].[Title], @p1 AS [value2], @p2 AS [value3], @p3 AS [value4], @p4 AS [value5], @p5 AS [value6], @p6 AS [value7], @p7 AS [value8]
FROM [dbo].[Assets] AS [t0]
UNION
SELECT @p8 AS [value], @p9 AS [value2], [t1].[Abbreviation], @p10 AS [value3], @p11 AS [value4], @p12 AS [value5], @p13 AS [value6], @p14 AS [value7], @p15 AS [value8]
FROM [dbo].[SportPositions] AS [t1]
) AS [t2]
UNION
SELECT @p16 AS [value], [t3].[Title], @p17 AS [value2], @p18 AS [value3], @p19 AS [value4], @p20 AS [value5], @p21 AS [value6], @p22 AS [value7], @p23 AS [value8]
FROM [dbo].[Assets] AS [t3]
) AS [t4]
这是有效的sql,并且可以正常工作。由于各种原因,我们无法将生产系统升级到.net 4,有人知道我可以在.net 3.5中解决这个问题吗?这是一个更新的答案-在3.5中,优化似乎无法关闭。我在LinqPad中尝试了很多方法,只要有一个C表达式不是从列派生的,查询编译器就会将其从SQL中删除 所以我们需要一些从列表达式派生的东西,但我们可以强制它始终为null 这里有一个解决方案,我已经能够开始工作-编写一个条件表达式,当一个列值等于它本身时返回null;因此总是返回null。这不会很好,因为3.5中的Linq to Sql在优化查询时表现得非常积极,我们必须对每个需要的null使用唯一的比较,例如使用==in one,then!=下一步等等;当我们修改它来处理空值时,它会变得更加丑陋,如果你必须对一个可空的列进行这种攻击: 我只是从您的代码中挑选出可以看到的列名,但您可能希望使用不同的列名:
select new PlayerUpdateInfo
{
FirstName = recruit.FirstName,
LastName = recruit.LastName,
RecruitId = recruit.RecruitId,
Date = asset.CreateDate,
UpdateMessage = "New Full Game Added",
// Defaults for union support
Team = recruit.FirstName = recruit.FirstName ? null : "",
UpdateComments = recruit.FirstName != recruit.FirstName ? "" : null,
TeamId = recruit.LastName = recruit.LastName ? null : "",
State = recruit.LastName != recruit.LastName ? "" : null
};
在LinqPad中,我在生成的SQL中为使用?:”的每个语句获取一个列表达式。表达式的另一方面是因为SQL抱怨CASE语句有多个null
很明显,这个解决方案除了像sin一样难看之外,还取决于有多少列可供您进行这些伪比较,以及L2S映射了多少个唯一的比较
团队、更新注释、状态为空字符串或空。因此,您应该为这两种情况提供相同的值。
如果使用默认比较器,则UpdateMessage不同,因此对象也不同。所以你可以用concat代替union。
有趣的问题。你试过做一个超级简单的例子吗?你能在简化的例子中重现同样的问题吗?试着用一个有9个参数的构造函数代替。也许LINQ的行为会有所不同。你能在Anon上联合,并在联合后转换到PlayerUpdateInfo吗?这不是答案,但我想知道这是否是创建优化的SelectAs PlayerUpdateInfo。我无法在一个简单的示例中得到错误,但是它看起来像null和string。select中的空文本在对待null时会有一些不同,“select null as[field]”和“select@p0 as[field]”时会有一个string.Empty参数。我猜GetFirstQuery和GetSecondQuery都返回IQueryable?刚到家,我会看看是否能想出一个发生这种情况的简单例子。是的,这两个函数都返回IQueryableYeah,这就是我知道这是一个与常数相关的优化,因为在同一个select语句中使每个常数不同会改变字段的数量。问题是它需要我做一些事情,比如把其中一个字段变成一个空格,这会改变queryoh的意思。我要说的是,nullstring技巧不起作用,它仍然在优化:该死,我们必须尝试不同的值then@KallDrexx-已更新我的答案。LINQtoSQL3.5查询编译器在优化方面表现得非常出色;我想我已经找到了一个解决办法,但它太肮脏了。
select new PlayerUpdateInfo
{
FirstName = recruit.FirstName,
LastName = recruit.LastName,
RecruitId = recruit.RecruitId,
Date = asset.CreateDate,
UpdateMessage = "New Full Game Added",
// Defaults for union support
Team = recruit.FirstName = recruit.FirstName ? null : "",
UpdateComments = recruit.FirstName != recruit.FirstName ? "" : null,
TeamId = recruit.LastName = recruit.LastName ? null : "",
State = recruit.LastName != recruit.LastName ? "" : null
};