Hibernate Envers在OneToMany JoinTable

时间:2017-07-24 14:37:50

标签: java spring hibernate hibernate-envers

嗨,我强迫Envers出问题。每个类都扩展包含@GeneratedAuto id等的BaseEntity。有两个实体:

@Audited
@Entity
public class HandballInjury extends Injury {

  @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  @JoinTable(name = "HandballDictionaryFact")
  private List<HandballDictionaryFact> handballDictionaryFacts = new ArrayList<HandballDictionaryFact>();
  private HandballTimeOfInjury timeOfInjury;

  ...
}

并且

@Audited
@Entity
@Table(name = "handballDictionaryFact")
public class HandballDictionaryFact extends DictionaryFact{
  ...
}

*父母双方都有@Audited注释。我的问题是,当我在HandballInjury上使用AuditEntity查找方法时,它会返回所有属于伤害但不关心revisionId的dictionaryFacts的正确伤害。在数据库中,一切都正确保存。我认为如果表已加入,那么envers看看id是否正确而不查看修订版。 Hibernate Envers版本:5.1.0.Final

编辑1:

我发现我没有通过SessionFactory.openSession()打开新会话。因为这个envers进入1 LevelCache来获取数据。我修好了,但没有帮助。这是如何启动查询:

  result = getReader().find(HandballInjury.class, ((HandballInjury) object).getId(), revisionNumber);

也许我应该写自己的查询?

我注意到下面的查询还会返回HandballDictionaryFacts_aud中的所有实体,而不是指定的revisionNumber。

 List<HandballDictionaryFact> dictionaryFact = getReader().createQuery()
                .forEntitiesAtRevision(HandballDictionaryFact.class, revisionNumber).getResultList();

编辑2: 我发现find查询正在寻找handballDictionaryFact,RevNumber小于或等于handballInjury.RevNumber。我现在的问题是,我可以强迫他们看起来只是平等吗?查询的一部分:

        and handballdi1_.REV=(
        select
            max(handballdi2_.REV) 
        from
            dictionaryfact_AUD handballdi2_ 
        where
            handballdi2_.DTYPE='HandballDictionaryFact' 
            and handballdi2_.REV<=?
            and handballdi1_.id=handballdi2_.id
    ) 

第一次编辑的查询还会检查revNumber是否小于或等于。

1 个答案:

答案 0 :(得分:0)

  

我的问题是,当我在HandballInjury上使用AuditEntity查找方法时,它会返回所有属于受伤但尚未关注revisionId的dictionaryFacts的正确伤害。在数据库中,一切都正确保存。我认为如果表格已经加入,那么envers就会看到id是不正确的,而不是修改版本。

由于审计跟踪的实际工作方式,这是不可能的。

如果查看审计表,您会注意到在许多情况下,在审计表中为实体的主键提供了修订号,以允许同一实体主键的多个条目

+----+-----+---------+---------+
| ID | REV | REVTYPE | DATA    |
+----+-----+---------+---------+
|  1 |   1 |       0 | Initial |
+----+-----+---------+---------+
|  1 |   2 |       1 | Updated |
+----+-----+---------+---------+
|  1 |   3 |       2 |         |
+----+-----+---------+---------+

正如您在此图中所示,此处的表有3行用于插入实体的相同实体主键(REVTYPE = 0),更新(REVTYPE = 1)和删除(REVTYPE = 2)。

如果此表与另一个实体相关联,我们还需要考虑REV值,以确保根据创建修订时的关联点确定关联是正确的。

让我们考虑另一个指向上表ID = 1的实体。如果我们不考虑REV,那么我们不知道应该如何填充相关审核实体实例上的DATA字段。它应该是Initial还是Updated

这是必须考虑REV字段的另一个原因。

  

发现我没有通过SessionFactory.openSession()打开新会话。因为这个envers进入1 LevelCache来获取数据。我已经修好了,但没有帮助。

我认为重要的是要澄清这里Envers使用自己的L1C实现,该实现独立于Hibernate Session使用的实现。

Envers使用自己的实现,因为它实例化的对象不是真正的托管实体,而只是构造的对象使用实体对象布局来表示给定修订版本中该实体的状态。时间。

我不清楚为什么你必须改变任何与会话管理相关的东西,除非你的代码做了其他不明确的事情。

HandballInjury injuryAtRevision = getReader()
  .find( HandballInjury.class, handballInjury.getId(), revisionNumber );

上述查询基本上会查看Envers L1C是否包含该给定主键和修订版的HandballInjury实例。如果是这样,它会返回它;否则它会从数据库中获取它。

返回的实例将表示生成指定HandballInjury值时的revisionNumber状态,包括任何经过审核的关联。

  

也许我应该写自己的查询?

为什么,你还没有在这里明确澄清这个问题。如上所述,查询完全符合其预期目的。

  

我注意到下面的查询还会返回HandballDictionaryFacts_aud中的所有实体,而不是指定的revisionNumber。

 List<HandballDictionaryFact> dictionaryFact = getReader().createQuery()
   .forEntitiesAtRevision( HandballDictionaryFact.class, revisionNumber )
   .getResultList();

这是预期的行为。

如果我们假设我们有两个事实,一个是在修订版1创建的,另一个是修订版2,上面使用了revisionNumber=2,那么在那个时刻,你有2个实体被定义,不是吗?

我可以在这里看到改进java-doc以使其更清晰,但这是预期的行为。

  

编辑2:我发现find查询正在寻找handballDictionaryFact,RevNumber小于或等于handballInjury.RevNumber。我现在的问题是,我可以强迫envers看起来只是等于

如果您希望明确并获取超出查询默认范围的特定修订版本的实体,则可以添加其他谓词以返回该类型的结果。

 List<HandballDictionaryFact> dictionaryFact = getReader().createQuery()
   .forEntitiesAtRevision( HandballDictionaryFact.class, revisionNumber )
   .add( AuditEntity.revisionNumber().eq( 2 ) )
   .getResultList();

采用与以前相同的假设,在修订版1中创建的事实和在修订版2中创建的事实,这将返回包含在修订版2中专门创建的事实的单个条目。