【问题标题】:Return a Specific Revision of An Object返回对象的特定版本
【发布时间】:2017-12-04 12:00:56
【问题描述】:

我想让我的 Envers 返回具有最高修订但仍低于给定修订号的实体。

我想出的是以下内容:

@PersistenceContext
private EntityManager em;

@Test
public void test() throws Exception {
    final Number before = AuditReaderFactory.get(this.em).getRevisionNumberForDate(new Date(Long.MAX_VALUE));

    final UserEntity user = new UserEntity().loginName("one");
    doInTransaction(() -> this.em.persist(user));

    final Number middle = AuditReaderFactory.get(this.em).getRevisionNumberForDate(new Date(Long.MAX_VALUE));

    user.setLoginName("two");
    doInTransaction(() -> this.em.persist(user));

    final Number after = AuditReaderFactory.get(this.em).getRevisionNumberForDate(new Date(Long.MAX_VALUE));

    Assert.assertEquals(new ArrayList<>(), getRevisions(before));
    Assert.assertEquals(Arrays.asList(user), getRevisions(middle));
    Assert.assertEquals(new ArrayList<>(), getRevisions(after));
}

private void doInTransaction(Runnable magic) {
    try {
        this.em.getTransaction().begin();
        magic.run();
        this.em.getTransaction().commit();
    } catch (final Exception e) {
        this.em.getTransaction().rollback();
        throw new RuntimeException(e);
    }
}   

private List<UserEntity> getRevisions(Number revisionNumber) {
    final AuditReader auditReader = AuditReaderFactory.get(this.em);
    try {
        return auditReader.createQuery().forRevisionsOfEntity(UserEntity.class, true, false)
                .add(AuditEntity.revisionNumber().maximize().computeAggregationInInstanceContext()) // the highest revision possible
                .add(AuditEntity.revisionNumber().le(revisionNumber)) // as long as the revision is below or equal to revisionNumber
                .getResultList();
    } catch (final NoResultException e) {
        return null;
    }
}

不起作用的方法是getRevisions(Object, Number)。它没有返回 before 修订版(这是正确的),它仍然没有返回 middle 修订版(不正确,现在实体存在!),然后返回 after 修订版(也不正确,实体已删除)。

当我们查看生成的 SQL 时,这种行为的原因就很清楚了:

SELECT * from user_aud u 
    WHERE u.REV = (
        SELECT MAX (v.REV) 
            FROM user_aud v 
            WHERE v.id=u.id
        ) 
    AND u.REV <= ? ORDER BY u.REV asc

u.REV &lt;= ? 部分应该在内部查询中。它现在生成的方式 Hibernate 决定最大修订为 3,然后什么都不选择,因为 rev 应该低于 2。

我似乎无法弄清楚如何修复查询,并且关于该主题的文档很少。我尝试删除 computeAggregationInInstanceCont(),但代码的行为方式没有变化。

获取低于用户定义值的最高版本的正确查询是什么?

【问题讨论】:

    标签: java hibernate hibernate-envers


    【解决方案1】:

    您应该能够获取低于指定值的最高修订号,如下所示:

    AuditReaderFactory.get( session )
      .createQuery()
      .forRevisionsOfEntity( EntityClass.class, true, true )
      .addOrder( AuditEntity.revisionNumber().desc() )
      .add( AuditEntity.id().eq( entityId ) )
      .add( AuditEntity.revisionNumber().le( userSuppliedValue ) )
      .setMaxResults( 1 )
      .singleResult();
    

    这将按降序排列所有修订并返回第一个条目。结果集中的行将针对具有主键 entityIdEntityClass 实体,并应用必须使用小于或等于提供的值的修订号审计实体的限制。

    【讨论】:

    • 好的,这仅适用于一个结果。在实践中,我们有许多由该方法返回的实体(因此是列表)。你知道该怎么做吗?
    • 我不确定我是否理解为什么您会在列表中返回多个值。如果您同时指定单个实体类型和主键(如您的示例中所示),那么只有“列表”才有意义是该实体的所有修订。因此,您想要小于或等于提供的修订值的所有实体类型/主键对的最大修订?
    • 是的,添加 ID 是错误的。在创建一个简单的示例时,我没有意识到它会在多大程度上改变问题(以及答案)。我相应地改变了问题。我们想要返回表格查看特定修订号的“快照”。
    【解决方案2】:

    这个问题归结为正确设置括号:

    private List<UserEntity> getRevisions(Number revisionNumber) {
        final AuditReader auditReader = AuditReaderFactory.get(this.em);
        try {
            return auditReader.createQuery().forRevisionsOfEntity(UserEntity.class, true, false)
                    .add(AuditEntity.revisionNumber().maximize().computeAggregationInInstanceContext().add(AuditEntity.revisionNumber().le(revisionNumber)))
                    .getResultList();
        } catch (final NoResultException e) {
            return null;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-09
      • 1970-01-01
      • 2018-01-02
      • 2022-01-01
      相关资源
      最近更新 更多