Hibernate Envers Composite Id实体无法解析 [英] Hibernate Envers Composite Id Entity Cannot be Resolved

查看:157
本文介绍了Hibernate Envers Composite Id实体无法解析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的数据库中有一个带有额外字段的复合ID表,并且使用EmbeddedId java persistence注释来配置相应的实体模型。在我的应用程序中执行编辑时,一切正常。但是,当试图使用Hibernate Envers检索审计数据时,代码失败,给了我以下堆栈跟踪:

 由org .hibernate.QueryException:无法解析org.hibernate.persister.entity.AbstractPropertyMapping.propertyException中的com.mycompany.model.DesignContract_AUD $ b $的property_contract_id:(AbstractPropertyMapping.java:62)$ or 
。 hibernate.persister.entity.AbstractPropertyMapping.toType(AbstractPropertyMapping.java:56)
位于org.hibernate.persister.entity.AbstractEntityPersister.toType(AbstractEntityPersister.java:1801)
位于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)
在org。 hibernate.hql.internal.ast.tree.DotNode.resolve(DotNode.java:204)
at org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:109)
在org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:104)
在org.hibernate.hql.internal.ast.HqlSqlWalker.resolve(HqlSqlWalker.java:1013)$在org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1286)b
$ b。在org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.exprOrSubquery(HqlSqlBaseWalker.java:4699)$在org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:4169)b
$ b。在org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2134)$在org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2059)b
$ b。在org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2059)
在org.hibernate.hql.i nternal.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:813)
处org.hibernate.hql org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:607)
。 internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:311)
处org.hibernate.hql org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:259)
。 internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:262)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:190)

这里有两个主要问题。首先,Contract_Id不是一个字段。我的JoinColumn配置了正确的名称FK_CONTRACT。其次,我不明白为什么它试图为审计表使用java类名,而不是使用@Table注释中设置的名称,即CONTRACT_DESIGNS。我的课程如下:

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

私人列表< DesignContract>设计;
@OneToMany(mappedBy =pk.contract,fetch = FetchType.EAGER,cascade = {CascadeType.ALL},orphanRemoval = true)
@Fetch(value = FetchMode.SUBSELECT)
公开列表< DesignContract> getDesigns(){
返回设计;
}
public void setDesigns(List< DesignContract> designs){
this.designs = designs;



$ b @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实现Serializable {
private static final long serialVersionUID = 1L;

公共DesignContract(){

}
公共DesignContract(合同合同,设计设计){
pk.setContract(合同);
pk.setDesign(design);
}

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

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

私人双重目标;
@Column(name =GOAL,nullable = true,insertable = true,updatable = true,precision = 5,scale = 2)
@Basic
public Double getGoal(){
返回this.goal;
}
public void setGoal(Double goal){
this.goal = goal;



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

私人合约;
私人设计设计;

@ManyToOne
公共合约getContract(){
返回合约;
}
public void setContract(Contract contract){
this.contract = contract;
}

@ManyToOne
公共设计getDesign(){
return design;
}
public void setDesign(Design design){
this.design = design;




$ b toString(),hashCode()和equals ()方法是为所有三个模型实现的,为简洁起见我省略了它们。



我用于检索审计信息的测试代码非常基本,因为我是大多数情况下只是做一些事情正在发挥作用的概念证明,并且可以初始化附属于我的主合同实体的延迟初始化记录。当我调用DesignContract列表的size()方法时,会发生错误,根据我发现的其他帖子,这是强制使用Hibernate Enver的ListProxy的方法。

  AuditReader reader = AuditReaderFactory.get(sessionFactory.openSession()); 
列表<号码> revisionsContract = reader.getRevisions(Contract.class,contractId);
(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(合约);
}

为了进行调试,我将show_sql设置为true, Hibernate试图调用size()时没有意义:

 从com.mycompany.model.DesignContract_AUD中选择e__ e__其中e __ contract_id =:contract_id和e__.originalId.REVISION_NUMBER.id =(从选择最大com.mycompany.model.DesignContract_AUD(E2 __ originalId.REVISION_NUMBER.id)e2__其中e2__.originalId.REVISION_NUMBER.id< =:。修订和e__.originalId.design = e2__.originalId.design和e __。originalId.contract = e2 __。originalId.contract)和REVISION_TYPE!=:delrevisiontype 

同样,没有contract_id字段,所以我不知道从给定DesignContract和DesignContractId的模型中的注释以及使用com.mycompany.model.DesignContract_AUD是我根本无法理解的东西。我甚至添加了@AuditTable注释,并将其指向CONTRACT_DESIGNS_AUD表,但这并没有改变任何内容。在执行正常操作(例如在我的应用程序中编辑和保存合同)时,审计信息已正确添加到CONTRACT_DESIGNS_AUD表中,我可以直接通过直接sql查询信息。我很遗憾,为什么审计阅读器会发生这种情况。我的应用程序中有多个复合ID实体,它们都以相同的方式配置,并且它们都遇到相同的错误,具有未知的contract_id参数以及用于查询中的审计表的java类名称。我曾试图配置我的模型以使用@IdClass注释而不是@EmbeddedId,但这只能帮助解析查询中的表名 - 它仍然尝试基于contract_id进行过滤,当然,它的状态无法解析。 / p>

我使用Hibernate 5.2.10.FINAL,在阅读该复合Id实体之后升级到的Hibernate无法与早期版本的Hibernate Envers一起工作 - https://hibernate.atlassian.net/browse/HHH-7625



对于我做错的任何帮助,我们将不胜感激。

解决方案

问题你正面临一个明确的错误。当我们在 @IdClass 映射的支持时> HHH-7625 ,我们没有正确说明 @EmbeddedId



我有在这个问题上记录了一个JIRA问题 HHH-11770 ,该问题已得到解决并将包括在5.2.11.Final发布。


I have a composite ID table with an additional field in my database, and the corresponding entity model configured using the EmbeddedId java persistence annotation. When performing edits in my application, everything works fine. However, when attempting to retrieve Audit data using Hibernate Envers, the code fails, giving me the following 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)

There are two major problems there. First, Contract_Id is not a field. I have the JoinColumn configured with the proper name of "FK_CONTRACT". Second, I don't understand why it's trying to use the java class name for the audit table, instead of using the name set in the @Table annotation, which is "CONTRACT_DESIGNS". My classes are as follows:

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

The toString(), hashCode(), and equals() methods are implemented for all three models, I've just omitted them for brevity.

My test code for retrieving the audit information is incredibly basic, as I'm mostly just doing a proof of concept that things are working and that the lazily-initialized records attached to my main Contract entity can be initialized. The error occurs when I invoke the size() method of the DesignContract list, which according to other posts I've found is the way to force the intilization of Hibernate Enver's 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);
    }

For debugging purposes, I've set show_sql to true, and the query that Hibernate is attempting when size() is invoked doesn't make sense:

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

Again, there is no contract_id field so I don't know where it's getting that from given my annotations in the models for DesignContract and DesignContractId, and the use of com.mycompany.model.DesignContract_AUD is something I can't understand at all. I even added the @AuditTable annotation, pointing it to the CONTRACT_DESIGNS_AUD table, but that didn't change anything. When performing normal operations such as editing and saving a contract in my application, the audit information is properly added to the CONTRACT_DESIGNS_AUD table, where I can query the information directly via straight sql. I'm at a loss as to why this would be happening with the AuditReader. I have multiple composite ID entities in my application, and they are all configured the same way, and they all are experiencing the same errors, with an unknown contract_id parameter, and the java class name used for the audit table in the queries. I did attempt to configure my model to use the @IdClass annotation instead of @EmbeddedId, but that only helped resolve the table name in the query - it still attempted to filter based on contract_id which, of course, it states cannot be resolved.

I'm using Hibernate 5.2.10.FINAL, which I had upgraded to after reading that composite Id entities failed to work with earlier versions of Hibernate Envers - https://hibernate.atlassian.net/browse/HHH-7625

Any assistance as to what I'm doing wrong would be greatly appreciated.

解决方案

The problem you're facing a definite bug. It seems when we implemented support for @IdClass mappings in HHH-7625, we didn't account for @EmbeddedId correctly.

I have logged a JIRA issue HHH-11770 on this problem, which has been fixed and will be included in the 5.2.11.Final release.

这篇关于Hibernate Envers Composite Id实体无法解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆