Нужна помощь в превращении стандартного SQL запроса в JPA Criteria Query - PullRequest
0 голосов
/ 24 января 2020

У меня есть две таблицы:

Сотрудник

id
firstName
lastName
.
.
.

Обучение

id
employeeId
trainingName
trainingSuspsnseDate
trainingComplete

Когда я выполняю стандартный SQL запрос в MySQL Workbench, это выглядит так:

SELECT e.id, e.firstName, e.lastName, t.trainingName, t.trainingSuspenseDate, t.trainingComplete
FROM Employee e
JOIN Training t on t.employeeId = e.id
WHERE t.trainingSuspenseDate < CURDATE()
order by t.trainingSuspenseDate;

Теперь я хочу создать критерий запроса для того же запроса SQL, но у меня возникли проблемы с объединением , Вот что я попробовал, основываясь на своем поиске:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> employeeQuery = builder.createQuery(Employee.class);
Root<Employee> employee = employeeQuery.from(Employee.class);
Join<Employee, Training> training = employee.join(Employee_.ID);
employeeQuery.select(builder.construct(Employee.class,
    employee.get(Employee_.ID),
    employee.get(Employee_.firstName),
    employee.get(Employee_.lastName),
    training.get(Training_trainingName),
    training.get(Training_trainingSuspsnseDate),
    training.get(Training_trainingComplete)));

Однако я получаю сообщение об ошибке:

incompatible types: inference variable Y has incompatible equality constraints Templates,Integer where Y,X are type-variables:
Y extends Object declared in method <Y>join(SingularAttribute<? super X,Y>)
X extends Object declared in interface From

Я пробовал другие перестановки JOIN, но я получить разные ошибки. Я не могу найти точный «секрет» для создания этого запроса.

Join<Employee, Training> training = training.join(Training_.employeeId);

или

Join<Employee, Training> training = training.join(Training_.employeeId).join(Employee_.ID);

или

Join<Training, Employee> training = training.join(Training_.employeeId);

или

Join<Training, Employee> training = training.join(Training_.employeeId).join(Employee_.ID);

или

.
.
.

РЕДАКТИРОВАТЬ: Добавлены мои классы моделей

Сотрудник. java

@Entity
@Table(name = "employee")
@XmlRootElement
@NamedQueries(
        {
            @NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e"),
            @NamedQuery(name = "Employee.deleteAll", query = "DELETE FROM Employee e"),
            @NamedQuery(name = "Employee.countAll", query = "SELECT COUNT(e.ID) FROM Employee e")
        })
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @GeneratedValue
    @Column(name = "id")
    private Integer ID;

    @Basic(optional = true)
    @Column(name = "name_first")
    private String firstName;

    @Basic(optional = true)
    @Column(name = "name_last")
    private String lastName;

    @Basic(optional = true)
    @Column(name = "created_date")
    private String employeeDate;

    @Basic(optional = true)
    @Column(name = "personal_type")
    private String personnelType;

    public Employee() {
        ID = 0;
    }

    public Employee(Integer id) {
        this.ID = id;
    }

    public Integer getID() {
        return ID;
    }

    public void setID(Integer id) {
        this.ID = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmployeeDate() {
        return employeeDate;
    }

    public void setEmployeeDate(String employeeDate) {
        this.employeeDate = employeeDate;
    }

    public String getPersonnelType() {
        return personnelType;
    }

    public void setPersonnelType(String personnelType) {
        this.personnelType = personnelType;
    }

}

Обучение. java

@Entity
@Table(name = "training")
@XmlRootElement
@NamedQueries(
        {
            @NamedQuery(name = "Training.findAll", query = "SELECT t FROM Training t"),
            @NamedQuery(name = "Training.deleteAll", query = "DELETE FROM Training t"),
            @NamedQuery(name = "Training.countAll", query = "SELECT COUNT(t.ID) FROM Training t")
        })
public class Training implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @GeneratedValue
    @Column(name = "ID")
    private Integer ID;

    @Basic(optional = false)
    @Column(name = "employee_id")
    private String employeeId;

    @Basic(optional = false)
    @Column(name = "training_name")
    private String trainingName;

    @Basic(optional = false)
    @Column(name = "training_suspense_date")
    private Date trainingSuspenseDate;

    @Basic(optional = false)
    @Column(name = "training_complete")
    private Boolean trainingComplete;

    public Integer getID() {
        return ID;
    }

    public void setID(Integer ID) {
        this.ID = ID;
    }

    public String getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(String employeeId) {
        this.employeeId = employeeId;
    }

    public void setTrainingName(String trainingName) {
        this.trainingName = trainingName;
    }

    public String getTrainingName() {
        return trainingName;
    }

    public void setTrainingSuspenseDate(Date trainingSuspsenseDate) {
        this.trainingSuspsenseDate = trainingSuspsenseDate;
    }

    public Date getTrainingSuspenseDate() {
        return trainingSuspsenseDate;
    }

    public void setTrainingComplete(Boolean trainingComplete) {
        this.trainingComplete = trainingComplete;
    }

    public Boolean getTrainingComplete() {
        return trainingComplete;
    }
}

Ответы [ 4 ]

1 голос
/ 05 февраля 2020

Я могу понять, что у вас есть метамодель, сгенерированная для вашего запроса. Таким образом, лучшим способом будет расширение определения вашей сущности следующим образом:

Вы должны добавить отображение в своем классе Training:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "employeeId")
private Employee employee;

Затем в своем классе Employee добавьте опозит ссылка:

@OneToMany(mappedBy = "employee")
private Set<Training> trainings = new HashSet<>();

Затем измените свой критерий запроса на:

Join<Employee, Training> training = employee.join(Employee_.trainings);
0 голосов
/ 11 февраля 2020

Это сообщение об ошибке - несовместимые типы: переменная логического вывода Y имеет несовместимые ограничения на равенство - это указание на то, что вам необходимо внимательно просмотреть ТИПЫ ДАННЫХ столбцов, к которым вы присоединяетесь. Должны быть одинаковые типы данных с обеих сторон для сравнения производительности и скорости.

0 голосов
/ 05 февраля 2020

Глядя на классы вашей модели, сущности не связаны напрямую (хотя employeeId в Training должен быть внешним ключом, он не определяется как таковой в отношениях сущностей. Итак, если вы sh для работы с существующими объектами, без их изменения, вам потребуется следующее:

  1. POJO (например, EmpRes), который отображает атрибуты согласно предложению select. CritQuery должен быть инициализирован на этот POJO как -

CriteriaQuery<EmpRes> criteriaQuery = builder .createQuery(EmpRes.class);

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

Код будет выглядеть следующим образом -

        criteriaQuery.select(builder.construct(EmpRes.class, employee
        .get(Employee_.getAttribute("ID").getName()), employee
        .get(Employee_.getAttribute("firstName").getName()), employee
        .get(Employee_.getAttribute("lastName").getName()), training
        .get(Training_.getAttribute("trainingName").getName()),
        training.get(Training_.getAttribute("trainingSuspenseDate")
                .getName()), training.get(Training_.getAttribute(
                "trainingComplete").getName())));

        criteriaQuery.where(builder.equal(employee.get("ID"), training.get("employeeId")));
        List<EmpRes> employees = entityManager.createQuery(criteriaQuery).getResultList();

Однако, если объекты могут быть изменены (как должно быть идеальным дизайном), Сотрудник имеет Обучение (я). Таким образом, @OneToMany отношение между классами модели Employee и Training должно быть определено следующим образом -

Employee. java

@OneToMany(mappedBy="employee") private Set<Training> trainings = new HashSet<>();

Обучение. java

@ManyToOne @JoinColumn(name = "employeeId") private Employee employee;

Код, связанный с критериями запроса -

Join<Employee, Training> trainingJoin = employee.join(Employee_.getAttribute("trainings").getName());
criteriaQuery.select(builder.construct(EmpRes.class, employee
        .get(Employee_.getAttribute("ID").getName()), employee
        .get(Employee_.getAttribute("firstName").getName()), employee
        .get(Employee_.getAttribute("lastName").getName()),
        trainingJoin.get(Training_.getAttribute("trainingName")
                .getName()), trainingJoin.get(Training_.getAttribute(
                "trainingSuspenseDate").getName()), trainingJoin
                .get(Training_.getAttribute("trainingComplete")
                        .getName())));

Затем можно добавить дополнительное условие where на основе ваших требований. Хорошая ссылка на Criteria API: здесь .

0 голосов
/ 05 февраля 2020

Вы можете попробовать cross join. Родной sql немного отличается, но результат такой же, как ожидалось

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> employeeQuery = builder.createQuery(Employee.class);
Root<Employee> employee = employeeQuery.from(Employee.class);
Root<Employee> training= employeeQuery.from(Training.class);

employeeQuery.select(builder.construct(Employee.class,
    employee.get(Employee_.ID),
    employee.get(Employee_.firstName),
    employee.get(Employee_.lastName),
    training.get(Training_.trainingName),
    training.get(Training_.trainingSuspsnseDate),
    training.get(Training_.trainingComplete)))
.where(builder.equal(employee.get(Employee_.ID), training.get(Training_.employeeId)));
...