单表继承(休眠)的 JPA 2 标准查询

Posted

技术标签:

【中文标题】单表继承(休眠)的 JPA 2 标准查询【英文标题】:JPA 2 Criteria Query on Single Table Inheritance (Hibernate) 【发布时间】:2016-06-01 03:47:49 【问题描述】:

我的项目正在使用 JPA 2 和 Hibernate,并且有一个单表继承设置来处理两种类型的客户。当我尝试使用 Spring Data JPA 规范查询客户数据时,我总是得到不正确的结果。我认为这是因为我创建了错误的查询,但仍然不知道如何使它正确。

这是我的测试代码(我正在尝试按公司名称搜索客户):

@Test
public void test() 
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Customer> customerQuery = criteriaBuilder.createQuery(Customer.class);
    Root<Customer> customerRoot = customerQuery.from(Customer.class);
    Root<CompanyCustomer> companyCustomerRoot = customerQuery.from(CompanyCustomer.class);

    CriteriaQuery<Customer> select = customerQuery.select(customerRoot);
    select.where(criteriaBuilder.equal(companyCustomerRoot.get(CompanyCustomer_.companyName), "My Company Name"));

    TypedQuery<Customer> query = entityManager.createQuery(select);
    List<Customer> results = query.getResultList();

    assertEquals(1, results.size()); // always got size 2

日志中的SQL脚本:

Hibernate: 
    select
        customer0_.id as id2_16_,
        customer0_.type as type1_16_,
        customer0_.first_name as first_na8_16_,
        customer0_.last_name as last_nam9_16_,
        customer0_.company_name as company13_16_ 
    from
        customers customer0_ cross 
    join
        customers companycus1_ 
    where
        companycus1_.type='COMPANY' 
        and companycus1_.company_name=?

我的数据库中有两条记录:

insert into customers (id, type, company_name) values (1, 'COMPANY', 'My Company Name');

insert into customers (id, type, first_name, last_name) values (2, 'PERSONAL', 'My First Name', 'My Last Name');

我的单表继承设置:

@Entity
@Table(name = "customers")
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
public abstract class Customer     

    @Enumerated(EnumType.STRING)
    @Column(name = "type", insertable = false, updatable = false)
    private CustomerType type;
    private String contactNumber;


@Entity
@DiscriminatorValue("PERSONAL")
public class PersonalCustomer extends Customer           

    private String firstName;
    private String lastName;    


@Entity
@DiscriminatorValue("COMPANY")
public class CompanyCustomer extends Customer 

    private String companyName;


public enum CustomerType 

    COMPANY, PERSONAL;

【问题讨论】:

它将返回 2 行,如您所见,hibernate 生成的 SQL 中有一个交叉连接。请你能解释一下你想从数据库中获取什么 @SangramJadhav 我正在尝试按公司名称搜索客户。实际上我正在研究搜索功能,测试代码是用例之一。用户也可以按名字或姓氏进行搜索。 您需要两种不同的方法来搜索公司和个人。这样您就可以仅通过公司名称或客户名称进行查询。您的服务层可以根据 CustomerType 决定调用哪个方法 @SangramJadhav 感谢您的快速回复。由于客户实体中有一些公共字段。例如:联系人号码。如果我使用两种方法搜索不同的客户,我应该如何处理公共字段搜索,并且我必须处理分页。 那么你可以用一个实体代替两个实体来代表数据库表。您可以创建映射层以从该实体创建 DTO 对象。搜索时可以使用实体,具体需求可以使用映射层根据类型将实体映射到DTO对象。 【参考方案1】:

我找到了答案 JPA Criteria Query over an entity hierarchy using single table inheritance

解决方案: 使用 CriteriaBuilder.treat() 向下转换 Customer 实体,而不是使用 CriteriaQuery.from()

【讨论】:

以上是关于单表继承(休眠)的 JPA 2 标准查询的主要内容,如果未能解决你的问题,请参考以下文章

我可以在休眠中使用单表继承从扩展实体中选择所有超级对象吗?

如何将@UniqueConstraint 与单表继承(JPA)一起使用?

使用 SingleTable 进行休眠继承

JPA继承方式

在休眠中使用继承时如何仅获取一种实体?

传递给持久化的分离实体:JPA 继承