如何使用Java 8对父子实体进行分组

琼斯:

我正在尝试对一些实体进行分组,以将孩子放在父级上。

@Entity 
public class JournalEntry {
    Integer id;
    String message;
    Integer parentId;        
}

数据传输对象看起来像这样...

public class JournalDTO {
    public JournalDTO (Integer id, String message, List<JournalDTO> childEntries) {
        this.id = id;
        this.message = message;
        this.childEntries = childEntries;
    }
    Integer id;
    String message;
    List<JournalDTO> childEntries;
}

因此,我希望以一个没有父ID的List结束,而顶层则没有父ID,然后它们将具有一组子实体,并且在这些子实体中,它们也可能具有子实体。有没有办法做到这一点。我的想法是首先获得所有顶级条目,如下所示。

List<JournalEntry> journalEntries = service.fetchJournalEntries();
List<JournalEntry> topLevel = journalEntries.stream().filter(e -> null==e.getParentId()).collect(toList());
journalEntries.removeAll(topLevel);
List<JournalDTO> journalDTOs = topLevel.stream()
                            .map(tl -> new JournalDTO(tl.getId(), tl.getMessage(), new ArrayList<JournalDTO>()))
                            .collect(toList());

然后我将其余条目按父ID分组。

Map<Integer, List<JournalEntry>> childMap = journalEntries.stream().collect(groupingBy(Integer::getParentId));

然后,我可以遍历此映射并将childEntities添加到父实体,但这只会给我第二级,然后我必须确保没有子代的孩子,等等。有没有更好的方法?

尤金:

多么有趣的问题。首先,为了简单起见,我定义了一种方法:

private static JournalDTO toDTO(JournalEntry entry) {
    return new JournalDTO(entry.getId(), entry.getMessage(), new ArrayList<>());
}

比我定义的一些小计算Map可以帮助我快速搜索:

    Map<Integer, JournalEntry> identity = entries.stream()
            .collect(Collectors.toMap(JournalEntry::getId, Function.identity()));

    Map<Integer, Set<Integer>> map = entries.stream()
            .collect(Collectors.groupingBy(
                    x -> x.getParentId() == null ? -1 : x.getParentId(),
                    Collectors.mapping(JournalEntry::getId, Collectors.toSet())));

第一个应该很明显,它包含一个ID和一个ID配对JournalEntry

第二个将parentIds 保留为一组ID。基本上:

-1 == 1 // -1 meaning it has no parents
 1 == 2 // 1 has a child with id 2
 2 == 3, 4 // 2 has two children with id 3 and 4
 4 == 5, 6 // ... 

如果您考虑的话-例如,这就是我如何找到整个“家庭”的方式(请让我知道这里是否需要更多详细信息)。

其余的是带有递归方法的简单代码:

// get those that have no parents first
Set<Integer> ids = map.get(-1);

// this is the ultimate result 
List<JournalDTO> all = new ArrayList<>();

// for each entity with no parents, start searching in the map
ids.forEach(x -> {
     JournalDTO parentDTO = toDTO(identity.get(x));
     recursive(x, map, identity, parentDTO);
     all.add(parentDTO);
}); 

当然,最重要的部分是:

private static void recursive(
        Integer parentId,
        Map<Integer, Set<Integer>> map,
        Map<Integer, JournalEntry> identity,
        JournalDTO journalDTO) {

    Set<Integer> childrenIds = map.get(parentId);

    if (childrenIds != null && !childrenIds.isEmpty()) {
        childrenIds.forEach(x -> {
            JournalDTO childDTO = toDTO(identity.get(x));
            journalDTO.getChildEntries().add(childDTO);
            recursive(x, map, identity, childDTO);
        });
    }
}

我已经针对一个非常简单的案例(带有的案例==进行了测试,似乎对我来说效果很好。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何对2个子实体进行分组并获得这两个子实体的总数?

使用子实体的字段进行过滤

如何对父子行进行分组(TSQL)

使用实体框架进行分组

如何使用数据存储区 api 对子实体进行排序

Junit:测试父子实体

通过使用被查询实体的子实体的信息对Hibernate Criteria查询的结果进行排序

如何使用共享主键保存子实体

如何使用 Linq 过滤子实体?

如何自动删除子实体?

使用JSON模式进行验证时,它不是递归验证子实体吗?

如何 - 按键对列表进行分组并使用流 Java 8 拆分值

通过具有父子关系的对象对Java流进行分组

使用Java 8按时间间隔对LocalDateTime对象进行分组

使用自定义键对Java 8进行分组

使用Java 8流对列表项进行分组和求和

数据存储区使用gcloud-java创建子实体

Java 8流-对元组流进行分组

Java 8流:通过聚合进行分组

通过Java8-Streams进行分组

使用实体框架保存大型实体和子实体

如何级联更新到Hibernate的子实体

如何用谓词过滤子实体集合?

如何使用join fetch通过一个查询获取父实体及其子实体及其子实体

如何使用Java根据日期对月份进行分组并计算总数?

使用Java 8如何根据过滤条件按列表和分组进行过滤,并将其计数转换为Map

Java 8-如何使用流收集器对地图列表进行分组和求和

如何使用Java 8流和Lambda将FlatMap分组

如何使用流在Java 8中按值范围分组