Chcę użyć kryteriówUpdate do utworzenia zapytania aktualizującego w następujący sposób:

UPDATE <SOME TABLE>
SET SELECTED = !SELECTED
WHERE
[DYNAMIC QUERY HERE]

Najbliżej mogłem uzyskać kod:

public <T> Query createRevertSelectionQuery(Class<T> clazz, EntityManager em, Specification<T> s) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaUpdate<T> criteriaUpdate = cb.createCriteriaUpdate(clazz);
    Root<T> root = criteriaUpdate.from(clazz);
    Predicate p = cb.and(new Predicate[] {s.toPredicate(root, null, cb)});
    Expression<Boolean> e =cb.not((root.get("selected").as(Boolean.class)));
    Path<Boolean> selected = root.get("selected");
    criteriaUpdate.set(selected, e);
    criteriaUpdate.where(p);
    Query q = em.createQuery(criteriaUpdate);       
    return q;       
}

Ale to się nie udaje, ponieważ otrzymuję następujące zapytanie:

update com.redknee.suspense.mgt.model.Moc as generatedAlias0 
set generatedAlias0.selected = generatedAlias0.selected <> true 
where 
[dynamic query]

Dając mi błąd

Org.hibernate.hql.internal.ast.QuerySyntaxException: nieoczekiwany token: <> blisko wiersza 1, kolumna 118

Czy ktoś może pomóc?

2
Luis Marcilio Braga Oliveira 10 listopad 2018, 19:36

1 odpowiedź

Najlepsza odpowiedź

Nie jestem pewien, czy jest to błąd, czy po prostu nie ma być używany w ten sposób.

W przypadku klauzuli NOT i innych operandów działa jak urok. Jednak bez względu na to, czego spróbujesz, konstruktor zapytań Hibernate zawsze optymalizuje te nawiasy (moim zdaniem nadal może być dobrym nawykiem, aby zawsze używać nawiasów, ale to tylko opinia).

Jednym ze sposobów wymuszenia nawiasów jest użycie JPA Subquery. Zobacz poniższy przykład. Zauważ, że nieznacznie zmieniłem nazwy obiektów JPA według własnego gustu i nie uwzględniłem Specification, ponieważ nie ma to znaczenia dla tego rozwiązania:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaUpdate<T> update = cb.createCriteriaUpdate(clazz);
Root<T> from = update.from(clazz);
Path<Boolean> selected = from.get("selected");

// Subquery just "joins back" to the same row and
// returns a negated boolean value of "selected" from the original row
Subquery<Boolean> subSelect = update.subquery(Boolean.class);
Root<T> subFrom = subSelect.from(clazz);
subSelect.select(cb.not(selected));
subSelect.where(cb.equal(from.get("id"), subFrom.get("id")));

update.set(selected, subSelect);
1
pirho 11 listopad 2018, 12:37