Запрос критериев JPA для вложенного набора

У меня есть сущность Person внутри этой сущности. У меня есть вложенный набор сущностей для PersonNames. Существует связь OneToMany между Person и PersonNames, заключающаяся в том, что у человека может быть несколько имен.

    @XmlElementWrapper(name = "names")
    @XmlElement(name = "name")
    @OneToMany(mappedBy = "person", orphanRemoval = false, fetch = FetchType.EAGER)
    private Set<PersonNames> name;

Вы можете увидеть, как набор PersonNames определен выше.

Мне нужно создать запрос JPA Criteria для поиска всех сущностей Person, у которых есть объект PersonNames, совпадающий с firstName, middleName или lastName.

public List<Person> getPerson(String lastName, String middleName, String firstName) {
    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Person> criteria = builder.createQuery(Person.class);

    Root<Person> root = criteria.from(Person.class);
    criteria.select(root);

    if(!lastName.isEmpty() && lastName != null) {
        Predicate lastNameCondition = builder.equal( root.get(Person_.personId).get(PersonNames_.lastName), lastName);
        criteria.where(lastNameCondition);
    }

    TypedQuery<Person> query = em.createQuery(criteria);
    return query.getResultList();
}

Выше приведена моя попытка выполнить указанный запрос, однако я получаю следующую ошибку в части ".get(Person_.personId)" строки Predicate:

Метод get(SingularAttribute) в типе Path неприменим для аргументов (SingularAttribute)

Строка предиката может быть совершенно неправильной, но я не могу понять, как это сделать, и ничего из того, что я гуглю, похоже, не дает никаких результатов. Нужно ли для этого делать явное соединение?

Изменить: удален тег Hibernate, так как я понял, что это то, что хочет использовать наш сервер Wildfly, но мы не используем Hibernate в нашем коде.


person Eric    schedule 14.11.2018    source источник


Ответы (2)


Re: «не использовать Hibernate API в нашем коде» — он устарел.

У CriteriaApi есть несколько недоброжелателей, но, тем не менее, как только вы освоитесь, к нему можно будет довольно легко подойти.

@Entity
public class Person {
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @OneToMany(mappedBy="person")
    private Set<PersonName> names;

и заполнить его:

tx.begin();
Person p = new Person();
PersonName c1 = new PersonName(p, "F1", "M1", "L1"); 
PersonName c2 = new PersonName(p, "F2", "M2", "L2"); 
em.persist(p);
em.persist(c1);
em.persist(c2);
tx.commit();

и запросить его

em.clear();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Person> query = cb.createQuery(Person.class);
Root<Person> person = query.from(Person.class);
Join<Person, PersonName> names = person.join("names");
Predicate[] findNames = new Predicate[3]; 
findNames[0] = cb.equal(names.get("firstName"), "F1");
findNames[1] = cb.equal(names.get("middleName"), "M1");
findNames[2] = cb.equal(names.get("lastName"), "L1");
query.where(findNames);
List<Person> persons = em.createQuery(query).getResultList();
System.out.println(persons);
person K.Nicholas    schedule 15.11.2018
comment
Великолепно! Работал отлично! Большое спасибо, и вы говорите, что Hibernate устарел? - person Eric; 15.11.2018
comment
Я просто имею в виду, что API устарел. Hibernate по-прежнему является поставщиком JPA. stackoverflow.com/ вопросы/50073875/ - person K.Nicholas; 15.11.2018

Будет ли это работать?

Criteria c = s.createCriteria(Person.class);
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
c.createAlias("name", "name");
c.add(Restrictions.eq("name.lastName", lastName));
return c.list();
person Justin    schedule 15.11.2018
comment
Потенциально, но я идиот и понял, что наш сервер Wildfly хочет использовать Hibernate, поэтому я думал об этом, но мы не используем Hibernate API в нашем коде (мы можем, если мы не можем найти базовые критерии JPA способ сделать это). - person Eric; 15.11.2018