C# Linq用DefaultIfEmpty实现LeftJoin却返回InnerJoin结果的问题
C# LINQ 左连接实现错误原因说明
错误点分析
代码返回内连接结果,核心问题有2个:
- 调用的
Join方法本身就是内连接实现,逻辑是仅保留左右表键完全匹配的行,Agent中Group字段为null的行无法和Groups表的ID字段匹配,会被直接过滤,和是否给Groups调用DefaultIfEmpty()无关。 DefaultIfEmpty()放在Join的右侧数据源上完全不生效,左连接要求对GroupJoin产生的每个左表行对应的右表匹配分组调用DefaultIfEmpty(),才能让未匹配到右表的左表行保留下来。
正确实现逻辑
C# LINQ 实现左连接标准写法为 GroupJoin + SelectMany + 分组DefaultIfEmpty()组合,对应给出的正确代码逻辑:
- 第一步用
GroupJoin以Agents为左表关联Groups表,所有Agent行都会保留,匹配到的多个Group会被封装成分组和对应的Agent绑定 - 第二步用
SelectMany展开分组,同时对每个分组调用DefaultIfEmpty(),如果当前Agent没有匹配到任何Group,分组会返回null值,避免该行被丢弃 - 第三步投影结果时判断Group是否为null,为空则赋值为
Empty即可完成左连接逻辑。
错误代码
Agents = new ObservableCollection<dynamic>((await _repository.GetAgentsAsync() ?? new Agent[] { }) .Join(Groups.DefaultIfEmpty(), a => a.Group, g => g.ID, (a, g) => new { ID = a.ID, AgentName = a.AgentName, Login = a.Login, AgentID = a.AgentID, IsDel = a.IsDel, Group = g == null ? "Empty" : $"{g.NameGroup} ({g.Num})" }));
正确代码
Groups = new ObservableCollection<Group>(await _repository.GetGroupsAsync() ?? new Group[] { }); Agents = new ObservableCollection<Agent>(await _repository.GetAgentsAsync() ?? new Agent[] { }); AgentsGroups = new ObservableCollection<dynamic>(Agents.GroupJoin(Groups, a => a.Group, g => g.ID, (a, g) => new { Agent = a, Group = g}) .SelectMany(ag => ag.Group.DefaultIfEmpty(), (a,g) => new { Agent = a.Agent, Group = g }) .Select ( ag => new { ID = ag.Agent.ID, AgentName = ag.Agent.AgentName, Login = ag.Agent.Login, AgentID = ag.Agent.AgentID, IsDel = ag.Agent.IsDel, Group = ag.Group == null ? "Empty" : $"{ag.Group.NameGroup} ({ag.Group.Num})" }));
内容的提问来源于stack exchange,提问作者Vladimir
相关产品推荐
相关产品推荐

