java - JPA - 如何使用实体继承中的 criteriaBuilder.construct 填充 DTO

标签 java hibernate spring-boot jpa spring-data-jpa

我有这些(最小和部分)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 个结果。

我们的 hibernate 输出如下所示:

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?有更好的方法吗?

谢谢。 :)

最佳答案

首先让我感谢您提出的格式非常好的问题 - 您做得很好,制作了 minimal, complete, and verifiable example 。我认为您不想将结果投影到您所描述的此类中。拥有一个具有 salaryhourlyWage 值的类意味着您必须一直检查 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);

关于java - JPA - 如何使用实体继承中的 criteriaBuilder.construct 填充 DTO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53016311/

相关文章:

java - java中返回相同的公共(public)IP地址

java - 在 Spring Boot 中在后台运行线程并能够 Autowiring

java - 如何使用 RestTemplate 在 qpid 中创建队列?

java - 尝试使用 Spring 和扩展 Hibernate 的 JpaRepository 的自定义 GenericDao 接口(interface)来使用 EhCache

java - spring hibernate 异步任务问题 No Session found for current thread

java - Hibernate:批量和非批量插入生成相同数量的 SQL 查询

java - 在 Spring Boot 应用程序中对 @Value 注释字段实现约束

java - 比较同一类变量的最佳方法是什么?

java - 这个正则表达式在 Java 中是如何工作的?

java - 无法从 spring mvc portlet 中的 View 检索模型属性