Использование оператора Coalesce или Case в JPA

Как использовать coalesce или case statement в JPA 2 с помощью CriteriaBuilder

Для многих записей InitialBy будет пустым, и в результате employeeName для этих записей будет нулевым. Я хотел бы отобразить Сгенерировано системой, если employeeName имеет значение null для тех проектов, где инициированный сотрудником имеет значение null в таблице базы данных.

У меня есть следующие отношения в Entities

Проект

@Entity
@Table(name = "PROJECT") 
public class Project {

@Id
@Column(name = "PROJECTID")
private Long projectId;
....
....

@ManyToOne
@JoinColumn(name = "EMPLOYEENUMBER", referencedColumnName = "EMPLOYEENUMBER")
private Employee empNumber;

@ManyToOne
@JoinColumn(name = "INITIATEDBY", referencedColumnName = "EMPLOYEENUMBER")
private Employee initiatedBy;

Сотрудник

@Entity
@Table(name = "EMPLOYEES")
public class Employee {

@Id
@Column(name = "EMPLOYEENUMBER")
private String employeeNo;

@Column(name = "EMPLOYEENAME")
private String employeeName;
.....
.....

@OneToMany(mappedBy = "empNumber")
private Set<Project> employeeProject;

@OneToMany(mappedBy = "initiatedBy")
private Set<Project> employeeInitiatedBy;

.....

в классе DAOImpl у меня есть

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Project> c = cb.createQuery(Project.class);
Root<Project> emp = c.from(Project.class);
c.orderBy(cb.desc(emp.get("projectNo")));
c.select(emp);

TypedQuery<Project> q =  entityManager.createQuery(c);

я пробовал с

Coalesce<String> coalesce = cb.coalesce();
coalesce.value(emp.<String>get("employeeName"));
coalesce.value("System Generated");

Однако, когда я бегу, я получаю исключение, поскольку

java.lang.IllegalArgumentException: Unable to resolve attribute 
[employeeName] against path

Любая помощь в этом очень ценна.


person Jacob    schedule 29.07.2013    source источник


Ответы (1)


Первая проблема — возможное непонимание использования сущностей JPA в качестве результата запроса. Когда сущности используются в качестве результата запроса, они отражают состояние базы данных. Замена Employee.empName значением, отличным от единицы в базе данных, противоречит этому.

До определенного момента этого можно достичь с помощью CriteriaBuilder.construct. Объекты результата (которые также могут быть сущностями) создаются с помощью конструктора, который должен принимать все выбранные элементы в качестве аргумента. К сожалению, это не очень хорошо сочетается с графом объектов (в данном случае Project и связанным Employee).

Вторая проблема заключается в том, что в следующем get("employeeName") вызывается Project, и у него нет такого атрибута:

Root<Project> emp = c.from(Project.class);
...
coalesce.value(emp.<String>get("employeeName"));

В целом объединение можно использовать следующим образом (но из-за того, что было сказано выше, это само по себе не решает проблему):

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<String> c = cb.createQuery(String.class);
Root<Employee> emp = c.from(Employee.class);

CriteriaBuilder.Coalesce<String> coalesce = cb.coalesce();
coalesce.value(emp.<String>get("employeeName"));
coalesce.value("System Generated");
c.select(coalesce);

TypedQuery<String> q =  em.createQuery(c);
person Mikko Maunu    schedule 29.07.2013
comment
Микко, так что правильный способ использования coalesce - это coalesce.value(emp.<String>get("employeeName"));? - person Jacob; 30.07.2013
comment
Не в этом случае, потому что в данном коде, несмотря на его имя, emp не относится к Employee. Это Root‹Project› emp. У сотрудника есть атрибут employeeName, а у проекта его нет. Я добавлю пример использования объединения, чтобы ответить. - person Mikko Maunu; 30.07.2013