C# Linq DefaultIfEmpty 左连接

C# Linq DefaultIfEmpty LeftJoin

某些代理在组字段中为空。 我正在尝试执行 LeftJoin,但收到类似 InnerJoin 的结果(仅具有非空组的代理)

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})" }));

方法语法不使用 Join 来执行左连接样式 link,它使用 GroupJoin。如果你直接Join那么右边(Group)缺少一个元素就意味着左边(Agent)的元素消失了。

GroupJoin 将左侧的元素与右侧的多个匹配元素配对

Left
1, John
2, Mary
3, Joe

Right
1, The Street, 1996
1, The Avenue, 2002
2, The Road, 2010

约翰住在两个地方,玛丽住在一个地方。乔从未住过任何地方。 Left.GroupJoin(Right) 产生:

{1, John}, [ {1, The Street, 1996}, {1, The Avenue, 2002} ]
{2, Mary}, [ {1, The Road, 2010} ]
{3, Joe},  [ ]

GroupJoin 将保留左边的元素,如果没有匹配,则使右边的元素为空序列

如果您需要将其作为包含重复元素的列表退回,您可以对它进行 SelectMany,这会扩展 person:addresses 代表的列表列表。我会回来的。


DefaultIfEmpty 不启用左连接行为;如果调用它的序列具有零个元素,那么 returns 包含目标类型的一项(并具有该类型的默认值)的序列只是一种便利。本质上就像:

public int[] DefaultIfEmpty(int[] input){
  if(input.Length == 0)
    return new int[1]; //a single integer, value 0 --> the default for int
  else
    return input;
}

你不需要在网上论坛;无论如何它都不是操作,因为如果有 0 个组,将其转换为单个 null 组的列表将表现相同(没有代理匹配)

如果您计划在您的分组中使用 SelectMany,您 想要 DefaultIfEmpty,因为 SelectMany 根本不会对 0 个元素的集合进行操作。因为 Joe 没有地址,SelectMany 会跳过他,他会从输出中消失


总而言之,这意味着你应该执行 GroupJoin,你真的不需要任何地方的 DefaultIfEmpty 因为你没有执行 SelectMany/你可以容忍在其他方面有 0 个 Agent 组。

我会使用更多的全名,因为不幸的是你要加入一个叫做 Group 的 class(我猜),并且 groupjoin 给你一个代理列表,并且每个代理在列表有一个匹配组的列表:

.GroupJoin(Groups, agent => agent.Group, group => group.ID, (agent, groupCollection) =>
    new {  
        agent.ID, 
        agent.AgentName,
        agent.Login,
        agent.AgentID, 
        agent.IsDel, 
        GroupNameAndNum = groupCollection.Select(g => $"{g.NameGroup} ({g.Num})").FirstOrDefault() ?? "Empty" 
    }
);

如果您使用 SelectMany(也许您的代理有 2 个组并希望单独列出它们,重复代理数据),它可能看起来像:

.GroupJoin(Groups, agent => agent.Group, group => group.ID, (agent, groupCollection) => new { Agent = agent, OneOrMoreGroups = groupCollection.DefaultIfEmpty() })
.SelectMany(
    agentWithGroupsCollection => agentWithGroupsCollection.OneOrMoreGroups,
    (agentWithGroupsCollection, groupsCollectionItem) =>

    new {  
        agentWithGroupsCollection.ID, 
        agentWithGroupsCollection.AgentName,
        agentWithGroupsCollection.Login,
        agentWithGroupsCollection.AgentID, 
        agentWithGroupsCollection.IsDel, 
        GroupNameAndNum = groupsCollectionItem == null ? "Empty" : $"{groupsCollectionItem.NameGroup} ({groupsCollectionItem.Num})"
    }
);