Java - API критериев - однонаправленный OneToMany - PullRequest
0 голосов
/ 06 августа 2020

Я пытаюсь получить номер лицензии от человека из таблицы процессов через API критериев. В основном из Process -> Person -> License

Однако таблица Person имеет однонаправленную связь OneToMany с таблицей License.

Итак, у меня есть следующие сущности:

@Entity
@Table(name = "Process")
public class Process {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "person_id")
    Person person;
}

@Entity
@Table(name = "Person")
public class Person {
    @Id
    @Column(name = "id",columnDefinition="INTEGER")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;
    
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "person")
    List<License> licenses;
}

@Entity
@Table(name = "License")
public class License {
    @Id
    @Column(name = "id",columnDefinition="INTEGER")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;
    
    @JoinColumn(name = "person_id")
    @ManyToOne(fetch = FetchType.LAZY)
    Person person;
    
    String licenseNumber;
}

В собственном запросе , результат, который я хотел бы выполнить sh, будет:

  select lic.license_number, * from Process process
  left join Person p on process.person_id = p.id
  left join License lic on lic.person_id = p.id;

Я пробовал использовать Join:

final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
final CriteriaQuery<Process> criteria = builder.createQuery(Process.class);
final Root<Process> rootSelect = criteria.from(Process.class);

//I don't really know how to join rootSelect (Process table), with License table... having the table Person in middle..
Join<Process, Person> personJoin = rootSelect.join("person");
Join<License, Person> licenseJoin = rootSelect.join("person");

, а также рассмотрел возможность использования подзапроса:

final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
final CriteriaQuery<Process> criteria = builder.createQuery(Process.class);
final Root<Process> rootSelect = criteria.from(Process.class);

Subquery sub = criteria.subquery(String.class);
Root subRoot = sub.from(License.class);
//How to select just the field 'license_number' below?
sub.select(subRoot);
sub.where(builder.equal(rootSelect.get("person").get("id"), subRoot.get("person")));

Мне понадобится номер_лицензии для фильтра (где) в конце.

Как лучше всего использовать такой фильтр, учитывая, что моя таблица root - это процесс?

1 Ответ

0 голосов
/ 10 августа 2020

Строго говоря, вам не нужно присоединять к таблицам процессов лицензию, вы должны присоединить к процессу с человеком и лицом с лицензией следующим образом:

Join<Process, Person> personJoin = rootSelect.join("person",JoinType.INNER);
Join<Person, License> licenseJoin = personJoin.join("licenses",JoinType.INNER);

Рекомендуется использовать метамодели и сущности , с ними Join будет выглядеть следующим образом (метамодель представлена ​​EntityName _):

Join<Process, Person> personJoin = rootSelect.join(Process_.person,JoinType.INNER);
Join<Person, License> licenseJoin = personJoin.join(Person_.licences,JoinType.INNER);

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

Добавляем условие фильтра

cq.where(cb.equal(licenceseJoin.get("licenseNumber"),LICENSE_NUMBER));
//cq.where(cb.equal(licenceseJoin.get(License_.licenseNumber),LICENSE_NUMBER));
...