[英]How to populate DTO class string fields using JPA CriteriaQuery on Entity having enum fields?
[英]JPA - How to populate a DTO using criteriaBuilder.construct from an Entity Inheritance
我有以下(最小和部分)JPA實體:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "type")
public abstract class Employee implements Serializable {
@Id
protected Long id;
...
}
@Entity
...
public class FullTimeEmployee extends Employee implements Serializable {
private BigDecimal salary;
...
}
@Entity
...
public class PartTimeEmployee extends Employee implements Serializable {
private BigDecimal hourlyWage;
private BigDecimal maxHoursWeek;
...
}
當前,我們正在使用spring-data-jpa進行查詢,如下所示:
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
List<Employee> findAll();
}
但是,這樣一來,我們就會遇到“ N + 1”問題和很多選擇,因此,我決定使用Criteria API並將其選擇到DTO中,如下所示:
public List<EmployeeDTO> findAll() {
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<EmployeeDTO> criteriaQuery = criteriaBuilder.createQuery(EmployeeDTO.class);
Root<Employee> root = criteriaQuery.from(Employee.class);
Root<FullTimeEmployee> fullTimeEmployeeRoot = criteriaBuilder.treat(root, FullTimeEmployee.class);
Root<PartTimeEmployee> partTimeEmployeeRoot = criteriaBuilder.treat(root, PartTimeEmployee.class);
criteriaQuery.select(criteriaBuilder.construct(EmployeeDTO.class,
root.get("id"), root.get("name"),
fullTimeEmployeeRoot.get("salary"),
partTimeEmployeeRoot.get("hourlyWage"))
);
return this.entityManager
.createQuery(criteriaQuery).getResultList();
}
這是我們的(示例)DTO
@Getter
@Setter
@AllArgsConstructor
public class EmployeeDTO {
private Long id;
private String name;
private BigDecimal fullTimeEmployeeSalary;
private BigDecimal partTimeEmployeeHourlyWage;
private BigDecimal partTimeEmployeeMaxHoursWeek;
...
}
但是,我們得到了0個結果。
我們的休眠輸出如下所示:
SELECT employee.id, employee.name, fullTimeEmployee.salary, partTimeEmployee.hourlyWage partTimeEmployee.maxHoursWeek ... FROM employees employee INNER JOIN fullTimeEmployees fullTimeEmployee on fullTimeEmployee.id = employee.id INNER JOIN partTimeEmployees partTimeEmployee on partTimeEmployee.id = employee.id
我的問題是:最好的方法是什么? 我如何將這些內部聯接轉換為左側聯接? 存在更好的方法嗎?
謝謝。 :)
首先,我要感謝您提出的格式很好的問題-您做了一個極簡,完整且可驗證的示例,做得很好。 我認為您不想將結果投影到您所描述的此類中。 擁有salary
或hourlyWage
值的類意味着您一直都在檢查是否為null,這是一個非常糟糕的設計決定。 更好的方法是從employeeRepository
獲取不同類型的列表,並使用面向對象的原則來處理混合類型。 這正是OOP發明的目的。
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "type")
public abstract class Employee implements Serializable {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
protected Long id;
public abstract BigDecimal getPay();
@Entity
public class FullTimeEmployee extends Employee {
private BigDecimal salary;
private int daysWorked;
@Override
public BigDecimal getPay() {
return salary
.multiply(BigDecimal.valueOf(daysWorked))
.divide(BigDecimal.valueOf(Year.now().length()), RoundingMode.HALF_DOWN);
}
@Entity
public class PartTimeEmployee extends Employee {
private BigDecimal hourlyWage;
private int hoursWorked;
@Override
public BigDecimal getPay() {
return hourlyWage.multiply(BigDecimal.valueOf(hoursWorked));
}
接着
BigDecimal sum = employeeRepo.findAll()
.stream()
.map(e->e.getPay())
.reduce(BigDecimal.ZERO, BigDecimal::add);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.