2

当我在 Postgres 中存储数据(使用 JPA 延迟加载)并将 javers 存储在 MongoDB 中时,我有这个异常“ENTITY_INSTANCE_WITH_NULL_ID”

Spring Boot:1.4.0.RELEASE

小树枝数据 JPA:1.4.0.RELEASE

贾维斯:2.3.0

如果对象是惰性对象,我调试并看到 ID 为空:org.javers.core.metamodel.type.EntityType:88 "Object cdoId = getIdProperty().get(instance);"

4

2 回答 2

8

当您将对象提交到 JaVers 时,它的先前版本将从 JaversRepository 加载并与当前版本(您刚刚传递给 commit() 方法的那个版本)进行比较。在这种情况下,JaVers 使用GlobalId查询类型名称 + 实体 ID 来查找以前的版本。这就是实体的 ID 不能为空的原因。

有两种可能:

  1. 如果空 ID 在此类中是正常的(根据您的域模型),您应该将其映射为JaVers 中的ValueObject
  2. 如果您使用的是 Hibernate,则延迟加载代理存在常见问题。对于某些查询,Hibernate 不会返回您的真实域对象,而是返回本质上为空的动态代理对象(因此为空 ID)。这种技术可能看起来很聪明,但在 Hibernate 初始化它们之前会使您的对象成为垃圾。JaVers 提供了HibernateUnproxyObjectAccessHook来进行清理:初始化和取消代理域对象。

    JaversBuilder.javers().withObjectAccessHook(new HibernateUnproxyObjectAccessHook()).build()

默认情况下,此挂钩在中启用,javers-spring-boot-starter-sql但在javers-spring-boot-starter-mongo. 如果您使用的是 Mongo starter,请自行创建一个 JaVers bean,并启用钩子,请参阅JaversMongoAutoConfiguration

于 2016-09-25T06:42:14.073 回答
0

我通过制作自己的访问挂钩解决了这个问题,并将其添加到 Javers 中

.withObjectAccessHook(新 EntityAccessHook()).build()

public class EntityAccessHook<T> extends HibernateUnproxyObjectAccessHook<T> {

  @Override
  public Optional<ObjectAccessProxy<T>> createAccessor(T entity) {
    Optional<ObjectAccessProxy<T>> accessProxy = super.createAccessor(entity);
    if (accessProxy.isEmpty() && entity instanceof AbstractUuidEntity) {
      return fromEntityInitializer((AbstractUuidEntity) entity);
    }
    return accessProxy;
  }

  private Optional<ObjectAccessProxy<T>> fromEntityInitializer(
      AbstractUuidEntity abstractUuidEntity) {
    return Optional.of(
        new ObjectAccessProxy(
            () -> abstractUuidEntity,
            abstractUuidEntity.getClass(),
            abstractUuidEntity.getId() == null ? UUID.randomUUID() : abstractUuidEntity.getId()));
  }
}
于 2020-05-13T14:33:46.123 回答