无法解析Hibernate Envers复合Id实体

无法解析Hibernate Envers复合Id实体,hibernate,hibernate-envers,Hibernate,Hibernate Envers,我有一个复合ID表,在数据库中有一个附加字段,并使用EmbeddedId java持久性注释配置了相应的实体模型。在应用程序中执行编辑时,一切正常。但是,当尝试使用Hibernate Envers检索审计数据时,代码失败,给出以下stacktrace: Caused by: org.hibernate.QueryException: could not resolve property: contract_id of: com.mycompany.model.DesignContract_AUD

我有一个复合ID表,在数据库中有一个附加字段,并使用EmbeddedId java持久性注释配置了相应的实体模型。在应用程序中执行编辑时,一切正常。但是,当尝试使用Hibernate Envers检索审计数据时,代码失败,给出以下stacktrace:

Caused by: org.hibernate.QueryException: could not resolve property: contract_id of: com.mycompany.model.DesignContract_AUD
    at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:62)
    at org.hibernate.persister.entity.AbstractPropertyMapping.toType(AbstractPropertyMapping.java:56)
    at org.hibernate.persister.entity.AbstractEntityPersister.toType(AbstractEntityPersister.java:1801)
    at org.hibernate.hql.internal.ast.tree.FromElementType.getPropertyType(FromElementType.java:393)
    at org.hibernate.hql.internal.ast.tree.FromElement.getPropertyType(FromElement.java:507)
    at org.hibernate.hql.internal.ast.tree.DotNode.getDataType(DotNode.java:660)
    at org.hibernate.hql.internal.ast.tree.DotNode.prepareLhs(DotNode.java:264)
    at org.hibernate.hql.internal.ast.tree.DotNode.resolve(DotNode.java:204)
    at org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:109)
    at org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:104)
    at org.hibernate.hql.internal.ast.HqlSqlWalker.resolve(HqlSqlWalker.java:1013)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1286)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.exprOrSubquery(HqlSqlBaseWalker.java:4699)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:4169)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2134)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2059)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2059)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:813)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:607)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:311)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:259)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:262)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:190)
这里有两个主要问题。首先,合同Id不是一个字段。我用“FK_合同”的正确名称配置了JoinColumn。其次,我不明白为什么它试图使用审计表的java类名,而不是使用@table注释中设置的名称,即“CONTRACT_Design”。我的课程如下:

@Entity
@DynamicInsert
@DynamicUpdate
@SelectBeforeUpdate
@Table(name="CONTRACTS")
@Audited
public class Contract implements Serializable {
    private static final long serialVersionUID = 1L;

    private List<DesignContract> designs;
    @OneToMany(mappedBy = "pk.contract", fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, orphanRemoval=true)
    @Fetch(value = FetchMode.SUBSELECT)
    public List<DesignContract> getDesigns() {
        return designs;
    }
    public void setDesigns(List<DesignContract> designs) {
        this.designs= designs;
    }
}


@Entity
@AssociationOverrides({
        @AssociationOverride(name = "pk.contract",
                joinColumns = @JoinColumn(name = "FK_CONTRACT")),
        @AssociationOverride(name = "pk.design",
                joinColumns = @JoinColumn(name = "FK_DESIGN")) })
@Table(name="CONTRACT_DESIGNS")
@Audited
public class DesignContract implements Serializable {
    private static final long serialVersionUID = 1L;

    public DesignContract () {

    }
    public DesignContract (Contract contract, Design design) {
        pk.setContract(contract);
        pk.setDesign(design);
    }

    private DesignContractId pk = new DesignContractId();
    @EmbeddedId
    public DesignContractId getPk() {
        return pk;
    }
    public void setPk(DesignContractId pk) {
        this.pk = pk;
    }

    @Transient
    public Contract getContract() {
        return getPk().getContract();
    }
    public void setContract(Contract contract) {
        getPk().setContract(contract);
    }

    @Transient
    public Design getDesign() {
        return getPk().getDesign();
    }
    public void setDesign(Design design) {
        getPk().setDesign(design);
    }

    private Double goal;
    @Column(name = "GOAL", nullable = true, insertable = true, updatable = true, precision = 5, scale = 2)
    @Basic
    public Double getGoal() {
        return this.goal;
    }
    public void setGoal(Double goal) {
        this.goal = goal;
    }
}

@Embeddable
public class DesignContractId implements Serializable {
    private static final long serialVersionUID = 1L;

    private Contract contract;
    private Design design;

    @ManyToOne
    public Contract getContract() {
        return contract;
    }
    public void setContract(Contract contract) {
        this.contract = contract;
    }

    @ManyToOne
    public Design getDesign() {
        return design;
    }
    public void setDesign(Design design) {
        this.design = design;
    }
}
@实体
@动态服务器
@动态铜日期
@选择BeforeUpdate
@表(name=“合同”)
@审计
公共类契约实现了可序列化{
私有静态最终长serialVersionUID=1L;
私人名单设计;
@OneToMany(mappedBy=“pk.contract”,fetch=FetchType.EAGER,cascade={CascadeType.ALL},orphanRemoving=true)
@Fetch(值=FetchMode.SUBSELECT)
公共列表getDesigns(){
退货设计;
}
公共设计(列表设计){
这个。设计=设计;
}
}
@实体
@联想超越({
@AssociationOverride(name=“pk.contract”,
joinColumns=@JoinColumn(name=“FK_合同”),
@关联超越(name=“pk.design”,
joinColumns=@JoinColumn(name=“FK_DESIGN”))})
@表(name=“合同设计”)
@审计
公共类DesignContract实现了可序列化{
私有静态最终长serialVersionUID=1L;
公共设计合约(){
}
公共设计合同(合同合同、设计){
pk.setContract(合同);
pk.setDesign(设计);
}
private designconstrucd pk=新designconstrucd();
@嵌入ID
公共设计压缩getPk(){
返回主键;
}
公共无效设置主键(设计收缩主键){
this.pk=pk;
}
@短暂的
公共合同{
返回getPk().getContract();
}
公共合同(合同){
getPk().setContract(合同);
}
@短暂的
公共设计{
返回getPk().getDesign();
}
公共空间设计(设计){
getPk().setDesign(设计);
}
私人双重目标;
@列(name=“GOAL”,nullable=true,insertable=true,updateable=true,precision=5,scale=2)
@基本的
公共双getGoal(){
返回这个目标;
}
公共目标(双重目标){
这个。目标=目标;
}
}
@可嵌入
公共类designContract实现了可序列化{
私有静态最终长serialVersionUID=1L;
私人合同;
私人设计;
@许多酮
公共合同{
退货合同;
}
公共合同(合同){
本合同=合同;
}
@许多酮
公共设计{
返回设计;
}
公共空间设计(设计){
这个。设计=设计;
}
}
toString()、hashCode()和equals()方法是为所有三个模型实现的,为了简洁起见,我刚刚省略了它们

我检索审计信息的测试代码非常基本,因为我主要只是做一个概念验证,证明一切正常,并且可以初始化附加到主合同实体的延迟初始化记录。当我调用DesignContract列表的size()方法时会发生错误,根据我找到的其他帖子,这是强制初始化Hibernate Enver的ListProxy的方法

    AuditReader reader = AuditReaderFactory.get(sessionFactory.openSession());
    List<Number> revisionsContract = reader.getRevisions(Contract.class, contractId);
    for (Number revisionNum : revisionsContract) {
        System.out.println("    revisionNum = " + revisionNum);
        Contract contract = reader.find(Contract.class, contractId, revisionNum);
        System.out.println(contract.getDesigns().size());
        System.out.println(contract.getDesigns());
        System.out.println(contract);
    }
AuditReader=AuditReaderFactory.get(sessionFactory.openSession());
列表修订合同=reader.getRevisions(Contract.class,contracd);
用于(编号修订编号:修订合同){
System.out.println(“revisionNum=“+revisionNum”);
合同=reader.find(Contract.class、contracd、revisionNum);
System.out.println(contract.getDesigns().size());
System.out.println(contract.getDesigns());
系统输出打印(合同);
}
出于调试目的,我将show_sql设置为true,调用size()时Hibernate尝试的查询没有意义:

select e__ from com.mycompany.model.DesignContract_AUD e__ where e__.contract_id = :contract_id and e__.originalId.REVISION_NUMBER.id = (select max(e2__.originalId.REVISION_NUMBER.id) from com.mycompany.model.DesignContract_AUD e2__ where e2__.originalId.REVISION_NUMBER.id <= :revision and e__.originalId.design = e2__.originalId.design and e__.originalId.contract = e2__.originalId.contract) and REVISION_TYPE != :delrevisiontype

从com.mycompany.model.DesignContract\u AUD e\u中选择e\u,其中e\u.contract\u id=:contract\u id和e\u.originalId.REVISION\u NUMBER.id=(选择max(e2\u.originalId.REVISION\u NUMBER.id=)从com.mycompany.model.DesignContract\u AUD e2\uuuuuuue2\uuuuu.originalId.REVISION\u NUMBER.id来看,您面临的问题是一个明确的bug。似乎在中实现对
@IdClass
映射的支持时,我们没有正确解释
@EmbeddedId


我已经记录了一个关于这个问题的JIRA问题,该问题已经修复,将包含在5.2.11.最终版本中。

我仍在关注这个问题,但至少要回答您的部分询问,它使用类名的原因是因为它是HQL,而不是SQL。我正在研究映射失败,请继续关注。这对HQL来说是有意义的。但是我发布的语句应该是原始HQL的SQL翻译。在我之前的所有调试中,将hibernate.show_SQL设置为true会为我提供从HQL生成的实际SQL语句。它始终具有实体的实际表名,因此我可以从控制台复制,粘贴到类似SQL Developer的内容中,然后运行查询,而无需任何修改修改。查看发布到我控制台的其他SQL语句,我没有看到使用类名的任何其他实例。所有其他语句都有正确的数据库表名。非常感谢。我将跟踪该问题并等待下一版本。实际上,是否有Hibernate 5.2.11的测试版或快照可以从Mave中提取n、 或者我应该只是比较一下吗