如何让JPA CriteriaQuery过滤抽象类子类属性

时间:2015-11-12 15:09:49

标签: java hibernate jpa jpa-2.1 criteriaquery

我无法使用构建器.treat()方法获取JPA查询以将AbstractAddress实体强制转换为其子类AddressStd

builder.equal( builder.treat(contracts.get("address"), 
                             AddressStd.class
                            ).get("houseNo"), std.getHouseNo()); 

背景

我使用JPA 2.1(使用Hibernate 5.0.2 FINAL)来映射遗留数据库,其中Customer有0:n个联系人,每个Contact都有AbstractAddress子类型AddressStdAddressPOB(邮政信箱)。联系人具有其他属性,但为了简单起见,它们未在下面显示。

域名模型

@Entity
@Table(name = "Customer")
public class Customer

    @Id @Column(name = "ID", nullable = false)
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_CUSTOMER_ID")
    @SequenceGenerator(name="SEQ_CUSTOMER_ID", sequenceName="SEQ_CUSTOMER_ID")
    private Long   id;

    @OneToMany(fetch = FetchType.LAZY, mappedBy="Customer", orphanRemoval=true, cascade=CascadeType.ALL)
    private Set<Contact> contacts;   
    ...
}


@Entity
@Table(name = "CONTACT")
public class Contact {

    @Id @Column(name = "CONTACT_ID", nullable = false)
    private Long  id;

    @Basic @Column(name = "ROLE", length = 30)
    @Convert(converter = ProfileTypeConverter.class)
    private ContactType type;

    @OneToOne(fetch = FetchType.LAZY, mappedBy="contact", orphanRemoval=true, cascade=CascadeType.ALL)
    private AbstractAddress address;
}    

@Entity
@Table(name = "ADDRESS")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorFormula( "case when PO_BOX_NUMBER is null then 'ADDRESS_STD' ELSE 'ADDRESS_POB' end" )
public abstract class AbstractAddress {

    @Id @Column(name = "ID", nullable = false, precision = 0)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ADDRESS")
    @SequenceGenerator(name = "SEQ_ADDRESS", sequenceName = "SEQ_ADDRESS")
    private Long id;

    @OneToOne
    @PrimaryKeyJoinColumn(name = "CONTACT_ID", referencedColumnName = "ID")
    private Contact contact;

    @Basic @Column(name = "POSTAL_CODE", length = 10)
    private String postcode;

    @Basic @Column(name = "CITY", length = 40)
    private String city;

    @Basic @Column(name = "COUNTRY", length = 2)
    @Convert(converter = CountryConverter.class)
    private Country country;

    @Basic(optional=false)
    @Column(name = "LNG_CODE", length = 2)
    @Convert(converter = LanguageConverter.class)
    private Language language;

    @Basic(optional=false)
    @Column(name = "STATUS", length = 1)
    @Convert(converter = BooleanActiveConverter.class)
    private Boolean isActive = true;
}

@Entity
@DiscriminatorValue("ADDRESS_STD")
public class AddressStd extends AbstractAddress {
    @Basic @Column(name = "HOUSE_NUMBER", length = 8)
    private String houseNo;

    @Basic @Column(name = "STREET_NAME", length = 30)
    private String street;

    ...
} 

@Entity
@DiscriminatorValue("ADDRESS_POB")
public class AddressPOB extends AbstractAddress {
    @Basic
    @Column(name = "PO_BOX_NUMBER", length = 8)
    private String poBoxNo; 
    ... 
}

JPA查询

构建查询用于检索AbstractAddress属性(city, postcode, country, language, isActive),但我无法检索AddressStdhouseNo, street)和{{的子类属性1}}(AddressPOB)分别作为

之类的陈述
poBoxNo

抛出运行时异常

builder.equal(builder.treat(contracts.get("address"), 
                             AddressStd.class
                            ).get("houseNo"), std.getHouseNo());

我之前使用了构建器.treat()方法来转换类型,它工作正常。但在这种情况下.treat()无法将地址转换为java.lang.IllegalArgumentException: Unable to locate Attribute with the given name [houseNo] on this ManagedType [com.compX.appY.domain.contacts.AbstractAddress] ?你们中的任何一个JPA大师都知道为什么,非常感谢,DaveT。

请参阅此处的CriteriaQuery构建器代码

AddressStd.class

0 个答案:

没有答案