Hibernate envers “无法评估 $HibernateProxy$.toString()”

huangapple go评论70阅读模式
英文:

Hibernate envers "cannot evaluate $HibernateProxy$.toString()"

问题

我正在使用Envers来审计我的实体。我的代码看起来有点像这样:

@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
@AuditOverride(forClass = Task.class, isAudited = true)
public class Job extends Task {
    // ...
}

@Inheritance(strategy = InheritanceType.JOINED)
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
public class Task {
    // ...
    @ManyToOne(fetch = FetchType.LAZY)
    @LazyToOne(value = LazyToOneOption.NO_PROXY)
    @Fetch(value = FetchMode.SELECT)
    @JoinColumn(name = "id_util")
    @Audited(targetAuditMode = RelationTargetAuditMode.AUDITED)
    private Utility utility;
}

@Entity
@DynamicInsert
@DynamicUpdate
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
public class Utility {
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(this.getClass().getName()).append("@").append(getId());
        builder.append("[");
        appendAttributeValues(builder);
        builder.append("]");
        return builder.toString();
    }

    public Long getId() {
        return id;
    }
}

当我尝试获取特定 job 实体的修订版本时,字段 utility 没有正确加载。相反,Hibernate 抛出了以下异常:

Method threw 'org.hibernate.exception.GenericJDBCException' exception. Cannot evaluate Utility$HibernateProxy$9GVDBIUC.toString()

其余的实体修订版本,包括字符串和数字,都能够正确加载。当审计和查询没有继承结构的其他实体时,我也不会遇到这个错误。

实体 JobTaskUtility_aud 表都被正确填充。可能导致这个错误的原因是什么?

英文:

I am using envers to audit my entities. My code looks somewhat like this

<!-- language: java -->

@Audited( targetAuditMode = RelationTargetAuditMode.NOT_AUDITED )
@AuditOverride( forClass = Task.class, isAudited = true )
public class Job extends Task
{...}

@Inheritance( strategy = InheritanceType.JOINED )
@Audited( targetAuditMode = RelationTargetAuditMode.NOT_AUDITED )
public class Task
{ 
    ...
    @ManyToOne( fetch = FetchType.LAZY )
    @LazyToOne( value = LazyToOneOption.NO_PROXY )
    @Fetch( value = FetchMode.SELECT )
    @JoinColumn( nam = &quot;id_util&quot; )
    @Audited( targetAuditMode = RelationTargetAuditMode.AUDITED )
    private Utility utility;
}

@Entity
@DynamicInsert
@DynamicUpdate
@Audited( targetAuditMode = RelationTargetAuditMode.NOT_AUDITED )
public class Utility
{
    @Override
    public String toString()
    {
        StringBuilder builder = new StringBuilder();
        builder.append( this.getClass().getName() ).append( &quot;@&quot; ).append( getId() );
        builder.append( &quot;[&quot; );
        appendAttributeValues( builder );
        builder.append( &quot;]&quot; );
        return builder.toString();
    }

    public Long getId()
    {
        return id;
    }
}

When I try to fetch the revisions of a certain job entity, the field utility is not loaded correctly. Instead, hibernate gives a

Method threw &#39;org.hibernate.exception.GenericJDBCException&#39; exception. Cannot evaluate Utility$HibernateProxy$9GVDBIUC.toString()

The rest of the entity revisions which consists of strings and numbers is loaded just fine. I also don't get this error when auditing and querying other entities which do not have an inheritance structure.

The _aud tables for the entities Job, Task and Utility are all filled correctly. What might be causing this error?

答案1

得分: 1

在使用链接对象之前,您应该像在这个答案中所说的那样“实例化”由Hibernate创建的代理对象:https://stackoverflow.com/a/2216603/3744622

Hibernate.initialize(entity);
if (entity instanceof HibernateProxy) {
    entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer()
        .getImplementation();
}
return entity;

或者,例如,使用特殊方法 unproxy

Object unproxiedObject = Hibernate.unproxy(proxiedObject);
英文:

Before using linked object you should "materialize" proxy-object created by hibernate, like sayed in this answer: https://stackoverflow.com/a/2216603/3744622

Hibernate.initialize(entity);
if (entity instanceof HibernateProxy) {
    entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer()
        .getImplementation();
}
return entity;

or, for instance, using special method unproxy:

Object unproxiedObject = Hibernate.unproxy(proxiedObject);

答案2

得分: 0

TLDR 问题出在不一致的审计数据上。当你开始审计已经存在的实体及其关系时,就会发生这种情况。

Solutionaud表中将所有实体数据复制为rev = 1revtype = 0。然后在revinfo表中插入rev=1revtstmp=0

详见当审计历史不完整时的安全Envers查询

Explanation 因为在集成Envers之前实体数据已经存在,所以审计表最初是空的。当你更新拥有对实体B的引用的实体A时,在A_aud中会创建审计记录,但在B_aud中不会。当尝试查询A的修订版本时,它会在空的B_aud中查找引用的实体B,导致EntityNotFoundException,该异常被包装在给定的GenericJDBCException中。

英文:

TLDR The reason is inconsistent audit data. It happens when you you start auditing already existing entities and their relations.

Solution Copy all entity data in the corresonding aud table with rev = 1,revtype = 0. Insert rev=1, revtstmp=0 into revinfo table.

See also Safe Envers queries when the audit history is incomplete

Explanation Because the entity data existed before envers is integrated, the audit tables are initially empty. When you update an entity A whichs owns a reference to entity B, an audit records is created in A_aud but not in B_aud. When A is queried for revisions it tries to look up the referred entity B in the emtpy B_aud and yields an EntityNotFoundException, which got wrapped up in the given GenericJDBCException.

huangapple
  • 本文由 发表于 2020年8月13日 21:14:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/63395997.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定