Java 在OneToMany JoinTable中找到Hibernate Envers

Java 在OneToMany JoinTable中找到Hibernate Envers,java,spring,hibernate,hibernate-envers,Java,Spring,Hibernate,Hibernate Envers,嗨,我在和恩弗斯讨论问题。每个类扩展包含@GenerateAuto id等的BaseEntity。有两个实体: @Audited @Entity public class HandballInjury extends Injury { @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinTable(name = "HandballDictionaryFact") private List<Han

嗨,我在和恩弗斯讨论问题。每个类扩展包含@GenerateAuto 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注释。我的问题是,当我在HandballInjury上使用AuditEntity find方法时,它会返回正确的伤害以及所有属于伤害的dictionaryFacts,但不考虑修订ID。在数据库中,所有内容都正确保存。我认为,若表被联接,那个么enver只查看id是否正确,而不查看修订。Hibernate Envers版本:5.1.0.Final

编辑1:

我发现我没有通过SessionFactory.openSession打开新会话。因此,envers正在进入1级缓存以获取数据。我已经修好了,但没用。这就是查询的启动方式:

  result = getReader().find(HandballInjury.class, ((HandballInjury) object).getId(), revisionNumber);
也许我应该写自己的查询

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

 List<HandballDictionaryFact> dictionaryFact = getReader().createQuery()
                .forEntitiesAtRevision(HandballDictionaryFact.class, revisionNumber).getResultList();
编辑2: 我发现find查询正在查找RevNumber小于或等于handballInjury.RevNumber的handballDictionaryFact。我现在的问题是,我能强迫恩弗斯看起来只有平等吗?查询部分:

        and handballdi1_.REV=(
        select
            max(handballdi2_.REV) 
        from
            dictionaryfact_AUD handballdi2_ 
        where
            handballdi2_.DTYPE='HandballDictionaryFact' 
            and handballdi2_.REV<=?
            and handballdi1_.id=handballdi2_.id
    ) 
来自第一次编辑的查询还检查revNumber是否小于或等于

我的问题是,当我在HandballInjury上使用AuditEntity find方法时,它会返回正确的伤害以及所有属于伤害的dictionaryFacts,但不考虑修订ID。在数据库中,所有内容都正确保存。我认为,若表被联接,那个么enver只查看id是否正确,而不查看修订

这是不可能的,因为审计跟踪实际上是如何工作的

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

+----+-----+---------+---------+
| ID | REV | REVTYPE | DATA    |
+----+-----+---------+---------+
|  1 |   1 |       0 | Initial |
+----+-----+---------+---------+
|  1 |   2 |       1 | Updated |
+----+-----+---------+---------+
|  1 |   3 |       2 |         |
+----+-----+---------+---------+
正如您在本图中所看到的,此处的表中有3行用于插入实体的同一实体主键REVTYPE=0、updated REVTYPE=1和deleted REVTYPE=2

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

让我们考虑指向上面表ID=1的另一个实体。如果我们不考虑REV,那么我们就不知道应该如何填充关联审计实体实例上的数据字段。它应该是初始的还是更新的

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

发现我没有通过SessionFactory.openSession打开新会话。因此,envers正在进入1级缓存以获取数据。我已经修好了,但没用

我认为在这里需要澄清的是,Envers使用自己的L1C实现,它独立于Hibernate会话使用的L1C实现

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

我不太清楚为什么您必须更改与会话管理相关的任何内容,除非您的代码正在执行其他模糊的操作

HandballInjury injuryAtRevision = getReader()
  .find( HandballInjury.class, handballInjury.getId(), revisionNumber );
上面的查询主要是查看Envers L1C是否包含给定主键和修订版的HandballInjury实例。若有,退回;;否则,它将从数据库中获取它

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

也许我应该写自己的查询

为什么,你在这里没有明确地阐明这个问题。如前所述,查询完全按照其预期执行

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

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

采用与之前相同的假设,在第1版创建一个事实,在第2版创建另一个事实,这将返回一个条目,其中包含在第2版中专门创建的事实。

Envers应应用REV谓词,以便与聚合根的任何关联,在本例中为HandballInjury,将等于或小于聚合根的值。如果您绝对确定它没有这样做,请打开JIRA记录单,并用一个简单的测试用例报告问题,该测试用例再现了错误。调试后,我发现envers从firstlevelcache而不是数据库获取数据。但不知道如何改变这一点。你是说它从会话的1LC或Envers的内部1LC获取数据,因为它们是两个不同的东西。你能用这个查询更新你的帖子吗?你是如何观察这种行为的?
 List<HandballDictionaryFact> dictionaryFact = getReader().createQuery()
   .forEntitiesAtRevision( HandballDictionaryFact.class, revisionNumber )
   .getResultList();
 List<HandballDictionaryFact> dictionaryFact = getReader().createQuery()
   .forEntitiesAtRevision( HandballDictionaryFact.class, revisionNumber )
   .add( AuditEntity.revisionNumber().eq( 2 ) )
   .getResultList();