【问题标题】:Get previous version of entity in Hibernate Envers在 Hibernate Envers 中获取以前版本的实体
【发布时间】:2010-10-22 01:49:05
【问题描述】:

我有一个由 Hibernate 加载的实体(通过 EntityManager):

User u = em.load(User.class, id)

此类由 Hibernate Envers 审核。如何加载以前版本的用户实体?

【问题讨论】:

    标签: java hibernate jboss hibernate-envers


    【解决方案1】:

    这是另一个版本,它查找与“当前”版本号相关的先前版本,因此即使您正在查看的实体不是最新版本,也可以使用它。它还处理没有先前修订的情况。 (em 被假定为以前填充的 EntityManager)

    public static User getPreviousVersion(User user, int current_rev) {
        AuditReader reader = AuditReaderFactory.get(em);
    
        Number prior_revision = (Number) reader.createQuery()
        .forRevisionsOfEntity(User.class, false, true)
        .addProjection(AuditEntity.revisionNumber().max())
        .add(AuditEntity.id().eq(user.getId()))
        .add(AuditEntity.revisionNumber().lt(current_rev))
        .getSingleResult();
    
        if (prior_revision != null)
            return (User) reader.find(User.class, user.getId(), prior_revision);
        else
            return null
    }
    

    这可以概括为:

    public static T getPreviousVersion(T entity, int current_rev) {
        AuditReader reader = AuditReaderFactory.get(JPA.em());
    
        Number prior_revision = (Number) reader.createQuery()
        .forRevisionsOfEntity(entity.getClass(), false, true)
        .addProjection(AuditEntity.revisionNumber().max())
        .add(AuditEntity.id().eq(((Model) entity).id))
        .add(AuditEntity.revisionNumber().lt(current_rev))
        .getSingleResult();
    
        if (prior_revision != null)
            return (T) reader.find(entity.getClass(), ((Model) entity).id, prior_revision);
        else
            return null
    }
    

    这种概括的唯一棘手之处是获取实体的 id。因为我用的是Play!框架,我可以利用所有实体都是模型的事实并使用((Model) entity).id 来获取 id,但您必须调整它以适应您的环境。

    【讨论】:

    • 不会forRevisionsOfEntity(clazz,false,true) 返回带有实例、修订信息和修订类型的Objec[]?如何将其类型转换为Number?
    • addProjection 更改此以返回修订号,有没有办法让它直接返回实体? (而不是之后再次运行查找)
    【解决方案2】:

    也许是这样(来自AuditReader docs)

    AuditReader reader = AuditReaderFactory.get(entityManager);
    User user_rev1 = reader.find(User.class, user.getId(), 1);
    
    List<Number> revNumbers = reader.getRevisions(User.class, user_rev1);
    User user_previous = reader.find(User.class, user_rev1.getId(),
      revNumbers.get(revNumbers.size()-1));
    

    (我对此很陌生,不确定我的语法是否正确,也许 size()-1 应该是 size()-2?)

    【讨论】:

    • 它确实需要size()-2 才能获得倒数第二个修订版
    • 为什么会有user_rev1? reader.getRevisions 接受 primaryKey 作为第二个参数。不是实体。所以你只需要AuditReader reader = AuditReaderFactory.get(entityManager); List&lt;Number&gt; revNumbers = reader.getRevisions(User.class, user.getId()); User user_previous = reader.find(User.class, user.getId(), revNumbers.get(revNumbers.size()-1));
    【解决方案3】:

    我想应该是这样的:

    final AuditReader reader = AuditReaderFactory.get( entityManagerOrSession );
    
    // This could probably be declared as Long instead of Object
    final Object pk = userCurrent.getId();
    
    final List<Number> userRevisions = reader.getRevisions( User.class, pk );
    
    final int revisionCount = userRevision.size();
    
    final Number previousRevision = userRevisions.get( revisionCount - 2 );
    
    final User userPrevious = reader.find( User.class, pk, previousRevision );
    

    【讨论】:

      【解决方案4】:

      在@brad-mace 的出色方法的基础上,我进行了以下更改:

      • 您应该传入您的 EntityClass 和 Id,而不是硬编码和假设模型。
      • 不要对 EntityManager 进行硬编码。
      • 没有点设置selectDeleted,因为删除的记录永远不能作为以前的修订返回。
      • 如果没有结果或找到超过 1 个结果,则调用 get single result 并抛出异常,因此要么调用 resultlist 要么捕获异常(此解决方案调用 getResultList 且 maxResults = 1)
      • 在一个事务中获取修订、类型和实体(移除投影,使用 orderBy 和 maxResults,并查询 Object[3])

      所以这是另一个解决方案:

      public static <T> T getPreviousRevision(EntityManager entityManager, Class<T> entityClass, Object entityId, int currentRev) {
          AuditReader reader = AuditReaderFactory.get(entityManager);
          List<Object[]> priorRevisions = (List<Object[]>) reader.createQuery()
                  .forRevisionsOfEntity(entityClass, false, false)
                  .add(AuditEntity.id().eq(entityId))
                  .add(AuditEntity.revisionNumber().lt(currentRev))
                  .addOrder(AuditEntity.revisionNumber().desc())
                  .setMaxResults(1)
                  .getResultList();
      
          if (priorRevisions.size() == 0) {
              return null;
          }
          // The list contains a single Object[] with entity, revinfo, and type 
          return (T) priorRevision.get(0)[0];
      }
      

      【讨论】:

        【解决方案5】:

        来自文档:

        AuditReader reader = AuditReaderFactory.get(entityManager);
        User user_rev1 = reader.find(User.class, user.getId(), 1);
        

        【讨论】:

        • 我不确定这是否适用于我,我想获得以前的版本,您的示例获得强制版本(在本例中为版本号 1)。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多