Spring Data Jpa Java8中使用filter和map提取db列数据

b0zn9rqh  于 2023-08-05  发布在  Spring
关注(0)|答案(1)|浏览(134)

关于员工的表具有以下数据:员工ID、员工姓名、经理ID和团队成员ID。每个员工将根据其团队规模有多个条目。假设团队中有5个其他成员的员工将有5行,其中员工ID和经理ID与每个团队成员的ID重复。
样品表:

employeeId | employeeName | managerId | teamEmployeeId |
-------------------------------------------------------
1000       | Alex         | 4000      | 1101           |
1200       | Bran         | 4100      | 1301           |
1200       | Bran         | 4100      | 1302           |
1000       | Alex         | 4000      | 1102           |
1200       | Bran         | 4100      | 1303           |
1000       | Alex         | 4000      | 1103           |
1200       | Bran         | 4100      | 1304           |
1200       | Bran         | 4100      | 1305           |
1000       | Alex         | 4000      | 1104           |

字符串
我们的目标是将每个员工的团队ID(以及经理ID)拆分到一个单独的数组中,以便稍后使用。
预期结果:

allIds:
1000
1200

teamIds for "Alex" :
1101
1102
1103
1104
4000

teamIds for "Bran" :
1301
1302
1303
1304
1305
4100


获取唯一员工ID的第一部分正在工作(基于此answer)。但是尝试使用employee id拆分团队成员时,返回的是第一个值,但次数是正确的。假设:一个有5个成员的团队返回一个包含5个成员的数组,其中第一个成员的id为所有成员的id。未添加经理的ID。
我使用的代码:

List<ViewData> list = getDataList();
        
String[] allIds = list.parallelStream()
    .map(ViewData::getId).distinct().toArray(String[]::new);
        
System.out.println(allIds.length + "\n");
        
for (String id : allIds) {
            
    String[] teamIds = list.parallelStream()
        .filter(row -> row.getId().equals(id))
        .map(ViewData::getTeamId).distinct()
        .toArray(String[]::new);
            
    teamIds = Arrays.copyOf(teamIds, teamIds.length+1 );
    teamIds[teamIds.length] = list.parallelStream()
        .filter(obj -> obj.getId().equals(id))
        .map(ViewData::getManagerId).toString();
    System.out.println(teamIds.length + "\n");
}


我知道这是个逻辑错误。我引用的所有filter()文档都显示语法是正确的。我的理解是,filter()返回id与我正在循环的id匹配的整行,map()从该行中取出团队成员的id,最后所有内容都以字符串数组的形式返回。
我哪里做错了?写代码还是理解这些函数是如何工作的?
编辑:
如果这样的表导致重复/重复行(特别是它应该出现的确切次数):
没有主键的视图(即,没有保证唯一的列)需要通过组合两个列而导出的复合主键,这两个列随后将是唯一的。

  • 为复合键组合创建单独的@Embeddable
  • 将其添加到主模型类:@EmbeddedId private UniqueId uniqueId;
  • 按照答案中的现有逻辑继续:
for (String id : allIds) {
    String[] teamIds = list.stream()
        .filter(row -> row.getUniqueId().getId().equals(id))
        .map(obj -> obj.getUniqueId().getTeamEmployeeId())
        .toArray(String[]::new);

    teamIds = Arrays.copyOf(teamIds, teamIds.length + 1);
    teamIds[teamIds.length - 1] = list.stream()
        .filter(obj -> obj.getUniqueId().getId().equals(id))
        .map(ViewData::getManagerId).findFirst().orElse("");            
    
    String empName = list.stream()
        .filter(obj -> obj.getUniqueId().getId().equals(id))
        .map(ViewData::getName).findFirst().orElse("");
}


更新:
这是一个非常复杂的解决方案,因为对数据结构的理解有限。使用Set的自动重复数据消除功能的更简单(略微冗余)解决方案:

Map<Integer, Set<Integer>> res = new HashMap<>();
employeeDetails.forEach(o-> {
    Integer empId = o.empId;
    if(!res.containsKey(empId)) res.put(empId, new HashSet<>());
        res.get(empId).addAll(Set.of(o.teamMemberId, o.managerId));
});
return res;


即使这也不是一个非常理想的解决方案。它对resMap及其值进行了大量访问和修改。但与前面的方法不同,这种方法只遍历记录列表一次。两种解决方案的一些基本基准测试表明,新方法对于1000大小的记录快3-4倍,对于100秒内的大小快10倍。
但是超过5000个会使两者更加接近,因为它们都被为存储结果和访问结果而创建的对象数量所困扰。

trnvg8h3

trnvg8h31#

根据问题和评论,您需要的是:

for (String id : allIds) {
    String[] teamIds = list.parallelStream()
                           .filter(row -> row.getId().equals(id))
                           .map(ViewData::getTeamId).distinct()
                           .toArray(String[]::new);

    teamIds = Arrays.copyOf(teamIds, teamIds.length + 1);
    teamIds[teamIds.length - 1] = list.parallelStream()
                                      .filter(obj -> obj.getId().equals(id))
                                      .map(ViewData::getManagerId)
                                      .findFirst()
                                      .orElse(null);

    System.out.println(teamIds.length + "\n");
}

字符串

相关问题