java - JPA - 如何使用来自实体继承的 criteriaBuilder.construct 填充 DTO
问题描述
我有这些(最小和部分)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
我的问题是:最好的方法是什么?我如何将这些 INNER JOIN 转换为 LEFT JOIN?有更好的方法吗?
谢谢。:)
解决方案
首先让我感谢您提出的格式非常精美的问题——您在制作一个最小的、完整的和可验证的示例方面做得很好。我认为您不想将结果投影到您描述的此类中。拥有一个具有 asalary
或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);
推荐阅读
- android - Places Api 在 android 中停止工作
- javascript - 未捕获的类型错误:无法读取未定义的属性“名称” - Reactjs
- java - 使用 Scanner 读取 .nextDouble 时出现 NoSuchElementException
- sorting - 在 Julia 中按多个元素对向量进行排序
- android - Firestore:从不同的文档请求集合
- c# - 无法使用 OLEDB 将连接字符串设置为 LocalDb
- css - 自动取最大高度 CSS 手写笔
- java - 在android中的自定义视图中将自定义样式设置为textviews
- delphi - Delphi Win64 调试器加载符号有限制吗?
- ios - 使用 AVAudioPlayer 无法通过 Swift 4 播放 .m4a