休眠环境 "cannot evaluate $HibernateProxy$.toString()"

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( nam = "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$HibernateProxyGVDBIUC.toString()

由字符串和数字组成的其余实体修订加载得很好。在审计和查询没有继承结构的其他实体时,我也没有收到此错误。

实体 JobTaskUtility_aud 表均已正确填写。可能导致此错误的原因是什么?

在使用链接对象之前,您应该“具体化”proxy-object 由休眠创建的对象,就像这个答案中所说的:

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

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

Object unproxiedObject = Hibernate.unproxy(proxiedObject);

TLDR原因是审计数据不一致。当您开始审核已经存在的实体及其关系时,就会发生这种情况。

解决方法复制audtable对应rev = 1,revtype = 0中的所有实体数据。将 rev=1revtstmp=0 插入 revinfo table.

另见 Safe Envers queries when the audit history is incomplete

说明因为实体数据在envers集成之前就已经存在,所以审计table最初是空的。当您更新拥有对实体 B 的引用的实体 A 时,会在 A_aud 中创建审计记录,但不会在 B_aud。当查询 A 的修订时,它会尝试在 emtpy B_aud 中查找引用的实体 B 并产生一个 EntityNotFoundException,它包含在给定的 GenericJDBCException.