C# Linq DefaultIfEmpty LeftJoin

Posted

技术标签:

【中文标题】C# Linq DefaultIfEmpty LeftJoin【英文标题】: 【发布时间】:2022-01-07 21:44:39 【问题描述】:

某些代理在组字段中为空。 我正在尝试进行 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)" ));

有什么问题?

谢谢大家,我找到答案https://***.com/a/21584913/13618303

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

【问题讨论】:

你是说组是空的吗? Agents 中会有 100 条唯一记录,Groups 中只有 80 条唯一记录? (所以 20 个代理没有组) 【参考方案1】:

方法语法不使用Join 来执行左连接样式链接,它使用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 不启用左连接行为;如果调用它的序列具有零个元素,则返回包含目标类型的一项(并具有该类型的默认值)的序列只是一种便利。本质上是这样的:

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个代理组其他方式。

我会使用更多的全名,因为不幸的是你加入了一个名为 Group 的类(我猜),并且 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)"
    
);

【讨论】:

以上是关于C# Linq DefaultIfEmpty LeftJoin的主要内容,如果未能解决你的问题,请参考以下文章

即使使用 DefaultIfEmpty,Linq 查询也不返回预期结果

加入 linq

Linq

linq 左连接

Linq 左连接

LINQ的左连接右连接内连接