我有3个表,例如alarmalarmTagalarm_alarmTagalarmalarmTag表具有ManyToMany关系。 alarm_alarmTag表正在映射alarmalarmTag表。

每个警报可以具有许多警报标签。例如,alarm1具有tag1tag2。因此,我想创建一个搜索过滤器,当我在该过滤器上选择tag1时,我想显示具有tag1的警报。

我已经用join做到了,但是问题是当我过滤tag1时,它在标签列上仅显示tag1,但该列上还有其他标签。

过滤前:

+------------------+
|     alarm table  |
+------------------+
| id  | tag        |
+------------------+
| 1   | tag1, tag2 |
| 2   | tag3, tag4 |
+------------------+


tag1过滤后:

+------------------+
|     alarm table  |
+------------------+
| id  |    tag     |
+------------------+
| 1   |    tag1    |(this column must also have `tag2`)
+------------------+


模型:

public class ActiveAlarm {

  @Id
  private Long id;

  @ManyToMany(cascade = CascadeType.PERSIST)
  private Set<AlarmTag> alarmTag;

}


控制器:

@GetMapping("/active")
public List<ActiveAlarmView> findAll(@RequestParam(required = false, defaultValue = "") List<Long> alarmTag) {

    var data = repository.findAll(ActiveAlarmSpecification.filter(alarmTag));

    return data.stream().map(record -> ActiveAlarmView.builder()
        .id(record.getId())
        .alarmTag(record.getAlarmTag()))
        .build()).collect(Collectors.toList());
}


过滤器规格:

public class ActiveAlarmSpecification {

  /**
   * Filter Specification.
   */
  public static Specification<ActiveAlarm> filter(List<Long> alarmTag) {
    return (root, query, cb) -> {
      query.distinct(true);

      ArrayList<Predicate> predicates = new ArrayList<>();

      if (!alarmTag.isEmpty()) {
        //***problem is in this line***
        predicates.add(root.join("alarmTag").get("id").in(alarmTag));
      }

      return cb.and(predicates.toArray(new Predicate[0]));
    };
  }
}


alarmTag型号:

public class AlarmTag {

  @Id
  private Long id;

  private String label;
}


这是我的请求链接:http://localhost:8080/api/test/v1/alarm/active?alarmTag=1

最佳答案

您将不得不分别获取它们或使用group by来汇总标签名称/标识(不幸的是,使用DTO进行投影)。

这背后的原因就是SQL会产生什么。查询将为+-,例如:

SELECT * FROM alarm a JOIN alarm_tag at ON ... JOIN tag t ON ... WHERE t.id IN (your,tags)


当您只有单个标签时,此查询结果将不包含其他ID与IN子句中的ID不同的其他标签

您将获得所需的所有警报,但是标记将从结果中过滤掉-这很准确,您在这里看到的内容

您可以尝试将root.join替换为root.fetch或尝试其他root.fetch,但是我不确定两者是否都可以。

关于java - JPA谓词标准构建器有很多麻烦,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57272108/

10-10 13:08