#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 критериев, чтобы быть более точным в ответах.