Как создать общий CriteriaQuery со свойством внешнего ключа?

Примеры сущностей:

@Entity
public class Employee {
    @Id
    @Column(name = "EMP_ID")
    private long id;
    ...
    @OneToMany(mappedBy = "owner")
    private List<Phone> phones;
    ...
}
@Entity
public class Phone {
    @Id
    private long id;    
    ...
    @ManyToOne
    @JoinColumn(name = "OWNER_ID")
    private Employee owner;
    ...
}

У меня есть общий класс, в котором запросы создаются в зависимости от типа объекта:

public class Repository<T>
{
    private Class<T> type;

    public List<T> select(String property, Object value) {
        EntityManager em = getEntityManager();
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<T> q = cb.createQuery(type);
        Root<T> root = q.from(type);
        Path<Object> path = root.get(property);
        query.where(path.in(value));
        query.select(q.select(root));
        TypedQuery<A> query = em.createQuery(q);
        return query.getResultList();
    }
}

Я хочу сгенерировать следующий запрос

SELECT * FROM PHONE WHERE OWNER_ID = ?

путем выполнения

Repository<Phone> repository;
List<Phone> phones = repository.select("owner.id", 1);

но это не работает, потому что "owner.id" не может быть найден. Хотя заявление

em.createQuery("SELECT p FROM Phone p WHERE p.owner.id = :id")

действительно работает.

Как я могу создать общий CriteriaQuery на основе типа T, в результате чего будет получен указанный оператор, не зная типа Employee?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
1 427
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы должны разделить свой property, а затем присоединиться к Employee. Для одного уровня соединения это может выглядеть так:

 String[] splitProperty = property.split(".");
 Join<Object, Object> owner = root.join(splitProperty[0]);
 Path<Object> path = owner.get(splitProperty[1]);
 q.where(path.in(value));
 ...

Конечно, если вам нужно более общее решение, вам придется перебирать разделенные части и присоединяться к другим таблицам.

Большое тебе спасибо! Я собираюсь реализовать это, как предлагается, в цикле для поддержки нескольких объединений.

Meini 05.12.2018 08:06

Вы можете присоединиться к родительскому объекту (Employee) из дочернего объекта (Phone) и запросить у joned объекта его свойство id.

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Child> cq = cb.createQuery(Child.class);
Root<Child> cr = cq.from(Child.class);
Join<Child, Parent> pj = cr.join("parent");
cq.where(cb.equal(pj.get("id"), 1));
List<Child> rl = em.createQuery(cq).getResultList();
System.out.println(rl);

Спасибо за ответ, но в этом примере мне нужно знать тип Child, но мой общий класс просто знает тип родителя.

Meini 05.12.2018 08:08

Другие вопросы по теме