我试图连接两个表中的数据,但我得到了奇怪的行为,并丢失了所需的信息。我不得不使用GroupJoin,因为某些项可能不像其他表那样存在于一个表中。
var joinedItems = context.TableOne.GroupJoin(context.TableTwo,
i => i.ItemID,
j => j.ItemID,
(i, j) => new
{
i,
j,
})
.Select(x => new
{
ID = x.i.ItemID,
MonthID = x.i.MonthID,
Rating = x.i.Rating,
ItemStatus = x.i.Status,
Tier = x.j.FirstOrDefault().Tier,
TierStatus = x.j.FirstOrDefault().Status,
}).Where(x => prevMonths.Contains(x.MonthID ?? 0)).ToArray();
prevMonths只是一个数组,它包含我想要的项目的月份ID(在本例中,前3个月)。作为参考,其中一个项目导致我丢失信息的问题:
Table One
----------
ItemID MonthID Rating Status . . .
96 5 12 Available
{ MonthID 2 - 4 are just straight up missing from the table }
96 1 9 Available
Table Two
---------
ItemID MonthID Tier Status . . .
96 5 5 Available
96 4 NULL N/A
96 3 NULL N/A
96 2 NULL N/A
当它被连接时,96的索引显示为
{ ID: 96, MonthID: 5, Rating: 12, ItemStatus: Available, Tier: , TierStatus: }
我不知道为什么它没有正确地将数据从TableTwo连接到TableOne。我唯一的假设是,GroupJoin在记录不存在时会有一些奇怪的行为,所以它不知道如何正确地将它们链接在一起。
这个问题涉及多个项目,这只是我关注的一个例子。
2条答案
按热度按时间xriantvc1#
似乎你想通过LINQ执行左连接。最正确的方法是设置实体之间的关系,并使用导航属性(即类似于
context.TableOne.Include(to => to.TableTwos)...
)。如果你仍然需要/想要通过LINQ执行左连接,你可以使用以下两种查询语法之一:
对于方法语法,您应该尝试以下操作:
oaxa6hgo2#
您观察到的行为是由GroupJoin的工作方式引起的。当您使用GroupJoin时,它将根据您指定的键(ItemID)将TableOne中的项与TableTwo中的项连接起来。如果TableTwo中没有与TableOne中某个特定项匹配的项,则该项的结果将是一个空集合。
在本例中,对于ItemID 96,表1中有两个条目,分别对应MonthID 5和1。但是,在TableTwo中,您有MonthID为5、4、3和2的条目。GroupJoin将仅联接两个表中具有匹配ItemID的项。因此,对于ItemID 96和MonthID 5,您将获得匹配,但对于MonthID 1,在TableTwo中没有对应的条目,因此Tier和TierStatus值为null。
尝试基于ItemID在两个表之间执行 join,然后基于MonthID过滤结果。你可以这样做:
这应该能够提供类似的结果,其中TableTwo中的数据基于ItemID和MonthID与TableOne连接。
基于 u/CodedRoses 反馈,更新了代码:
通过使用
DefaultIfEmpty()
,您可以确保对于TableOne
中的每个项(在TableTwo
中没有匹配项),您都可以获得一个集合,其中包含一个空项。这允许您在结果中包含TableOne
中的所有项。然后使用null条件运算符(?.
)来处理来自TableTwo
的项为null的情况。关于在
Select
语句之前按月份过滤的问题,问题在于Where
子句是在GroupJoin
之后应用的,因此它会从TableOne
中过滤掉在指定月份的TableTwo
中没有匹配项的项。通过将Where
子句移到GroupJoin
之前,可以确保只联接TableOne
中与指定月份匹配的项。