如何使用QueryDSL或Spring Data JPA规范执行层级实体的查询?

7

我有一个实体层次结构,类似于这个。除了一些常见属性外,一些属性仅由少数子类型共享:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Person {
    private String firstName;
    private String lastName

    ... further properties, getters and setters...
}

@Entity
public class Employee extends Person {
    private String salary;

    ... further properties, getters and setters...
}

@Entity
public class BoardMember extends Person {
    private String salary;

    ... further properties, getters and setters...
}

@Entity
public class ExternalMember extends Person {
    private String clearanceLevel;

    ... further properties, getters and setters...
}

@Repository
public interface PersonRepository extends JpaRepository<Person, Long>, QuerydslPredicateExecutor<Person> {

}

我正在使用QueryDSL根据动态筛选条件搜索人员,例如:

@Service
@Transactional
public class PersonService {

  @Autowired
  PersonRepository personRepository;

  public Page<Person> search(String firstName, String salary) {
    var searchCriterias = new BooleanBuilder();
    if (firstName != null) {
      searchCriterias.and(QPerson.firstName.eq(firstName));
    }
    if (salary != null) {
        searchCriterias.andAnyOf(
          QPerson.person.as(QEmployee.class).salary.eq(salary),
          QPerson.person.as(QBoardMember.class).salary.eq(salary),
        );
    }
    personRepository.findAll(searchCriterias);
  }
}

这似乎不是正确的方法,但是我遇到了很多错误,比如“salary”不是Person的成员。

处理分层实体搜索的各种方法有哪些?我更喜欢使用QueryDSL来保证类型安全,但使用Spring Data Specification的解决方案也可以。

编辑:使用15个以上不同的搜索条件可能会变得非常复杂。因此,我需要一种编程方法来制定它们。


我在这里回答了类似的问题:https://dev59.com/pbnoa4cB1Zd3GeqPNUf6#60246119 - Oleksii Valuiskyi
1
@alexvaluiskyi 使用规范API处理平面对象非常简单。我的问题在于实体的分层结构,这使得标准更加复杂。我需要将谓词转换为多个子类型,但Hibernate不喜欢这样做。 - MattDiMu
@ManuelJain 是的,这就是为什么Hibernate拒绝执行查询的问题所在。那么我该如何使用QueryDSL或Criteria API在这些字段上编程创建查询呢?有一些方法可以将QEntities“转换”为它们的子类型(http://www.querydsl.com/static/querydsl/latest/reference/html/ch03.html),但似乎并不起作用。 - MattDiMu
@MattDiMu 你尝试将你的存储库更改为以下内容了吗?public interface EmployeeRepository extends JpaRepository<Employee, Long>, QuerydslPredicateExecutor<Employee>然后使用它来执行你的findAll操作? - Manuel Jain
@ManuelJain 是的,但这并不能解决问题,因为它只允许搜索员工。我需要在多个不同的子类型中进行搜索! - MattDiMu
显示剩余2条评论
1个回答

1
我无法重现“不是Person的成员”错误,但我已成功获得了您查询的结果。
遵循Baeldung的教程并调整您问题中的代码,我成功地获得了结果而没有出现错误。这里是示例项目。希望对您有所帮助。
import javax.persistence.*;

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column
    private String firstName;

    @Column
    private String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Person() {
    }
}

import javax.persistence.Column;
import javax.persistence.Entity;

@Entity
public class BoardMember extends Person {

    @Column
    private String salary;

    public BoardMember(String firstName, String lastName, String salary) {
        super(firstName, lastName);
        this.salary = salary;
    }

    public BoardMember() {
    }
}

@Service
@Transactional
public class PersonService {

    @Autowired
    PersonRepository personRepository;

    public List<Person> search(String firstName, String salary) {
        var searchCriterias = new BooleanBuilder();
        if (firstName != null) {
            searchCriterias.and(QPerson.person.firstName.eq(firstName));
        }
        if (salary != null) {
            searchCriterias.andAnyOf(
                    QPerson.person.as(QEmployee.class).salary.eq(salary),
                    QPerson.person.as(QBoardMember.class).salary.eq(salary)
            );
        }

        var result = new ArrayList<Person>();
        for (Person person : personRepository.findAll(searchCriterias)) {
            result.add(person);
        }
        return result;
    }
}

1
感谢您的努力。不幸的是,这并不起作用。虽然没有出现Hibernate异常,但搜索功能无法正常工作,可能是因为有两个薪资属性混淆了QueryDSL或Hibernate。 在调试应用程序时,谓词看起来像这样:person.salary eq "salary" || person.salary eq "salary",它无法区分不同的子类型。 - MattDiMu
1
由于赏金即将到期,我已将其授予您,因为您提供了最接近的答案并付出了很多努力。但是我无法标记它为正确,因为搜索功能不正常,我不想让其他遇到同样问题的人感到困惑。 - MattDiMu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接