CriteriaBuilder.size() и аннотации Hibernate @Where

#sql #hibernate #jpa #spring-data-jpa #criteria-api

#sql #переход в спящий режим #jpa #spring-data-jpa #критерии-api

Вопрос:

У меня есть следующая настройка:

 @Entity
public class Function {
  private String name;

  @OneToMany(mappedBy = "function", cascade = CascadeType.ALL, orphanRemoval = true)
  @Where(clause = "type = 'In'") // <=== seems to cause problems for CriteriaBuilder::size
  private Set<Parameter> inParameters = new HashSet<>();

  @OneToMany(mappedBy = "function", cascade = CascadeType.ALL, orphanRemoval = true)
  @Where(clause = "type = 'Out'") // <=== seems to cause problems for CriteriaBuilder::size
  private Set<Parameter> outParameters = new HashSet<>();
}

@Entity
public class Parameter {
  private String name;

  @Enumerated(EnumType.STRING)
  private ParameterType type;

  @ManyToOne(fetch = FetchType.LAZY, optional = false)
  @JoinColumn(name = "function_id")
  private Function function;
}
  

Общая проблема, которую я пытаюсь решить, заключается в том, чтобы найти все функции, у которых есть outParameter функции с точным динамическим набором имен. Например. найти все функции с outParameter s, имена которых точно ('outParam1', 'outParam2')

Похоже, что это проблема с «точным реляционным разделением» в SQL, поэтому могут быть лучшие решения, но способ, которым я это сделал, выглядит следующим образом:

 List<String> paramNames = ...

Root<Function> func = criteria.from(Function.class);
Path outParams = func.get("outParameters");
Path paramName = func.join("outParameters").get("name");

...
// CriteriaBuilder Code
builder.and(
  builder.or(paramNames.stream().map(name -> builder.like(builder.lower(paramName), builder.literal(name))).toArray(Predicate[]::new)),
  builder.equal(builder.size(outParams), paramNames.size()));

  

Проблема, которую я получаю, заключается в том, что builder.size() , похоже, не учитывает @Where аннотацию. Поскольку «CriteriaBuilder code» вложен в общий, Specification который должен работать для любого типа объектов, я не могу просто добавить query.where() предложение.

Код работает, когда функция имеет 0 входных параметров, но он не работает, когда у него больше. Я взглянул на сгенерированный SQL и вижу, что он отсутствует:

 SELECT DISTINCT
  function0_.id AS id1_37_,
  function0_.name AS name4_37_,
FROM
  functions function0_
  LEFT OUTER JOIN parameters outparamet2_ ON function0_.id = outparamet2_.function_id
    AND (outparamet2_.type = 'Out') -- <== where clause added here
WHERE (lower(outparamet2_.name)
  LIKE lower(?)
  OR lower(outparamet2_.name)
  LIKE lower(?))
AND (
  SELECT
    count(outparamet4_.function_id)
  FROM
    parameters outparamet4_
  WHERE
    function0_.id = outparamet4_.function_id) = 2 -- <== where clause NOT added here
  

Приветствуется любая помощь (либо с другим подходом к проблеме, либо с обходным путем, чтобы builder.size() не работать).

Ответ №1:

Аннотация where находится в объекте function, в подзапросе вы не использовали этот объект, поэтому операция выполнена правильно, попробуйте использовать объект function в качестве корня подзапроса или реализовать where вручную.

Для следующего вопроса было бы рекомендовано включить полный код API критериев, чтобы быть более точным в ответах.