如何使用querydsl或spring data jpa规范对分层实体执行查询?

问题描述 投票:1回答:2

我有这样的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,我试图根据像这样的动态过滤器标准来搜索人员:

@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的解决方案也可以。

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

java hibernate spring-data-jpa querydsl
2个回答
0
投票

我不知道您的数据库架构,但是由于您使用的是InheritanceType.JOINED,因此有一个用于超类的表和一个用于每个子实体的表,它们都被联接了。假设子实体具有一列person_id,该列将其与父实体连接在一起。然后,您可以编写如下查询:

entityManager.createNativeQuery(
    "select p.* " +
    "from person p " +
    "left join employee e on e.person_id = p.id " +
    "left join board_member bm on bm.person_id = p.id " +
    "where (:firstName is null or p.first_name = :firstName) " +
    "and (:salary is null or e.salary = :salary or bm.salary = :salary);"
)
    .unwrap(org.hibernate.query.Query.class)
    .setParameter("firstName", firstName, StringType.INSTANCE)
    .setParameter("salary", salary, IntegerType.INSTANCE)
    .getResultList();

注意unwrap,让我们将setParameter与类型为Type的第三个参数一起使用。当传递的参数可能为null时,它是必需的,以便休眠模式始终可以确定其类型。


0
投票

我无法重现“不是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;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.