Как создать общий CriteriaQuery со свойством внешнего ключа? - PullRequest
0 голосов
/ 04 декабря 2018

Примеры объектов:

@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?

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Вы можете присоединиться к Родителю (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);
0 голосов
/ 04 декабря 2018

Вы должны разделить свой 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));
 ...

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

...