我遇到外连接问题。我发现这篇非常有用的stackoverflow文章: linq-full-outer-join 但是当我使用错误检索数据时,我的连接出现问题:
NotSupportedException: Unsupported overload used for query operator 'DefaultIfEmpty'.
以下是代码:
var query =
from i2 in (from sel in (from i in (from a1 in Activities
where a1.ActivityDate >= DateTime.Parse("4/15/2011")
&& a1.ActivityDate < DateTime.Parse("4/19/2011")
select new {
a1.ActivityDate,
a1.RecID} )
group i by new { i.RecID }
into g
select new {
g.Key.RecID,
MaxDate = g.Max(i => i.ActivityDate)})
join a in Activities on 1 equals 1
where (sel.MaxDate == a.ActivityDate && sel.RecID == a.RecID)
select new {
a.RecID,
a.UserName,
ActivityDate = a.ActivityDate.Date,
Sum1 = (a.StatusID == 7) ? 1 : 0,
Sum2 = (a.StatusID == 5) ? 1 : 0,
Sum3 = (a.StatusID == 4) ? 1 : 0})
group i2 by new {
UserName = i2.UserName,
ActivityDate = i2.ActivityDate
}
into g2
select new {
JoinId = (string)(g2.Key.ActivityDate + "_" + g2.Key.UserName),
ActivityDate = (DateTime)g2.Key.ActivityDate,
UserName = (string)g2.Key.UserName,
Sum1 = (int)g2.Sum(i2 => i2.Sum1),
Sum2 = (int)g2.Sum(i2 => i2.Sum2),
Sum3 = (int)g2.Sum(i2 => i2.Sum3),
};
var query2 = from s in ProdHistories
where s.CompletedDate >= DateTime.Parse("4/15/2011")
&& s.CompletedDate <= DateTime.Parse("4/19/2011")
select new {
JoinId = (string)(s.CompletedDate + "_" + s.UserName),
CompletedDate = (DateTime)s.CompletedDate,
UserName = (string)s.UserName,
Type1 = (int)s.Type1,
Type2 = (int)s.Type2,
Type3 = (int)s.Type3,
Type4 = (int)s.Type4,
Type5 = (int)s.Type5,
Type6 = (int)s.Type6,
Type7 = (int)s.Type7,
Type8 = (int)s.Type8,
};
var joinLeft = from ph in query2
join act in query
on ph.JoinId equals act.JoinId
into temp
from act in temp.DefaultIfEmpty(new {
JoinId = (string)ph.JoinId,
ActivityDate = (DateTime)ph.CompletedDate,
UserName = (string)ph.UserName,
Sum1 = default(int),
Sum2 = default(int),
Sum3 = default(int),
})
select new { ph.UserName,
ph.CompletedDate,
ph.Type1,
ph.Type2,
ph.Type3,
ph.Type4,
ph.Type5,
ph.Type6,
ph.Type7,
ph.Type8,
act.Sum1,
act.Sum2,
act.Sum3};
query.Dump(); // successfully dumps (in LinqPad) data - no nulls
query2.Dump(); // successfully dumps (in LinqPad) data - no nulls
joinLeft.Dump(); // raises: NotSupportedException: Unsupported overload used for query operator 'DefaultIfEmpty'.
我尝试了相同的外连接子句并使用固定数据,它可以工作:
var query = new[]
{
new { JoinId = "12345", ActivityDate = DateTime.Parse("1/1/2011"), UserName = "UID1", Sum1 = 10, Sum2 = 11, Sum3 = 12 },
new { JoinId = "23456", ActivityDate = DateTime.Parse("1/2/2011"), UserName = "UID2", Sum1 = 20, Sum2 = 21, Sum3 = 22 },
new { JoinId = "34567", ActivityDate = DateTime.Parse("1/3/2011"), UserName = "UID3", Sum1 = 30, Sum2 = 31, Sum3 = 32 },
};
var query2 = new[]
{
new { JoinId = "12345", CompletedDate = DateTime.Parse("1/1/2011"), UserName = "UID1", Type1 = 110, Type2 = 111, Type3 = 112, Type4 = 113, Type5 = 114, Type6 = 115, Type7 = 116, Type8 = 117 },
new { JoinId = "23456", CompletedDate = DateTime.Parse("1/2/2011"), UserName = "UID2", Type1 = 210, Type2 = 211, Type3 = 212, Type4 = 213, Type5 = 214, Type6 = 215, Type7 = 216, Type8 = 217 },
new { JoinId = "45678", CompletedDate = DateTime.Parse("1/5/2011"), UserName = "UID4", Type1 = 310, Type2 = 311, Type3 = 312, Type4 = 313, Type5 = 314, Type6 = 315, Type7 = 316, Type8 = 317 },
};
var joinLeft = from ph in query2
join act in query
on ph.JoinId equals act.JoinId
into temp
from act in temp.DefaultIfEmpty(new {
JoinId = (string)ph.JoinId,
ActivityDate = (DateTime)ph.CompletedDate,
UserName = (string)ph.UserName,
Sum1 = default(int),
Sum2 = default(int),
Sum3 = default(int),
})
select new { ph.UserName,
ph.CompletedDate,
ph.Type1,
ph.Type2,
ph.Type3,
ph.Type4,
ph.Type5,
ph.Type6,
ph.Type7,
ph.Type8,
act.Sum1,
act.Sum2,
act.Sum3};
joinLeft.Dump();
结果:
UserName CompletedDate Type1 Type2 Type3 Type4 Type5 Type6 Type7 Type8 Sum1 Sum2 Sum3
UID1 1/1/2011 12:00:00 AM 110 111 112 113 114 115 116 117 10 11 12
UID2 1/2/2011 12:00:00 AM 210 211 212 213 214 215 216 217 20 21 22
UID4 1/5/2011 12:00:00 AM 310 311 312 313 314 315 316 317 0 0 0
我看到another stackoverflow article其中Jon Skeet使用IEnumerable作为另一个上下文中此错误的解决方案的一部分,但我不太确定如何应用它。
感谢您提供任何线索!
答案 0 :(得分:1)
我认为post you took the code from也回答了你的问题(粗体是我的)。
这是写的,因为它在LINQ to Objects中。 如果LINQ to SQL 或者其他,默认情况下
DefaultIfEmpty()
的重载可能 不行。然后你必须使用条件运算符 有条件地获得价值。即,
var leftOuterJoin = from first in firstNames join last in lastNames on first.ID equals last.ID into temp from last in temp.DefaultIfEmpty() select new { first.ID, FirstName = first.Name, LastName = last != null ? last.Name : default(string), };
这就是答案,我可以通过使用
ToList()
将IQueryable转换为List来使我的代码正常工作。
如果您不希望join
在数据库上运行并且您对在对象上执行它们感到满意,那么这绝对是另一种选择。但是,如果有很多对象(它取决于多少个),这可能会影响性能。遵循通常的优化口号:测量,测量和测量。如果这无关紧要,ToList
将正常工作。