【问题标题】:How to perform queries on hierarchical entities using querydsl or spring data jpa specification?如何使用 querydsl 或 spring data jpa 规范对分层实体执行查询?
【发布时间】:2020-06-05 20:40:15
【问题描述】:

我有一个像这样的entity hierarchy。除了一些公共属性外,一些属性仅由少数子类型共享:

@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 我正在尝试根据动态过滤条件搜索 Persons,如下所示:

@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);
  }
}

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

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

edit:使用超过 15 种不同的搜索条件,搜索条件可能会变得非常复杂。所以我需要一种程序化的方法来制定它们。

【问题讨论】:

  • 我在这里stackoverflow.com/questions/60243712/…回答了类似的问题
  • 您可以使用 JPA 元模型使 Criteria api 类型安全
  • @alexvaluiskyi 使用平面对象的规范 api 是没有问题的。我的问题是我的实体的层次结构,这使得标准更加复杂。我需要将谓词转换为 hibernate 不喜欢的多个子类型。
  • 这里的问题不是只有 Employee 和 BoardMember 实体知道薪水,因此对于 PersonRepository,它是一个未知字段吗?
  • @ManuelJain 是的,这就是hibernate拒绝执行查询的问题。那么我如何使用 querydsl 或条件 api 以编程方式在这些字段上创建查询?有一些方法可以将 QEntities “转换”为它们的子类型 (querydsl.com/static/querydsl/latest/reference/html/ch03.html),但这似乎不起作用。

标签: java hibernate spring-data-jpa querydsl


【解决方案1】:

我无法重现“不是 Person 的成员”错误,但我已设法从您的查询中得到结果。

按照Baeldung's tutorial 并根据您的问题调整代码,我设法得到没有错误的结果。 Here 是示例项目。希望这会有所帮助

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;
    }
}

【讨论】:

  • 感谢您的努力。不幸的是,这不起作用。确实,没有休眠异常,但是搜索不能正常工作,可能是因为有 2 个工资属性会混淆 QueryDSL 或休眠。调试应用程序时,谓词如下所示:person.salary eq "salary" || person.salary eq "salary",它无法区分不同的子类型。
  • 由于赏金即将到期,我已将其授予您,因为您提供了最接近的答案并付出了很多努力。我仍然不能标记是正确的,因为搜索不能正常工作,我不想让其他人遇到同样的问题。
猜你喜欢
  • 2016-02-17
  • 1970-01-01
  • 2014-03-29
  • 2012-07-25
  • 2013-05-01
  • 2015-05-11
  • 2023-01-31
  • 2020-06-16
  • 2020-03-05
相关资源
最近更新 更多