2017-07-24 121 views
0

嗨,我强迫Envers问题。每类扩展包含@GeneratedAuto的ID等。有两个实体BaseEntity:休眠Envers找到OneToMany JoinTable

@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的字典数据的正确伤害。在数据库中,一切都保存正确。我认为,如果表加入,那么envers看起来只是如果id是正确的,而不看版本。休眠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: 我发现找到查询与RevNumber寻找handballDictionaryFact小于或等于handballInjury.RevNumber。我现在的问题是,我可以迫使envers只看起来平等吗?部分查询:

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

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

+0

Envers应当施加特别创建的事实中的单个条目'REV'谓词,以便聚合根的任何关联(在本例中为“HandballInjury”)将等于或小于聚合根的关联。如果您确信它没有这样做,请打开一个JIRA票据,并用一个简单的测试案例来报告问题,以重现错误。 – Naros

+0

调试后我发现envers从firstlevelcache而不是数据库获取数据。但不知道如何改变这一点。 – MrNetroful

+0

你是说它从Session的1LC或Envers的内部1LC中获取数据,因为它们是两回事。你可以用查询更新你的文章,以及你如何观察这种行为? – Naros

回答

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对于给定的主键和修改的实例。如果是这样,它会返回它;否则它从数据库中获取它。

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

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

为什么,您还没有澄清这个问题。如上所述,查询完全按照其意图执行的操作。

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

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

,这是预期的行为。

如果我们假设我们有两个事实,一个在修订版1创建,另一个在修订版2和上面使用revisionNumber=2,那么在那个时候,你有两个实体定义,你不知道?

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

编辑2:我发现查找查询正在查找与RevNumber小于或等于handballInjury.RevNumber的handballDictionaryFact。我现在的问题是,我可以强制envers看仅相当于

如果你想是明确的,并在以后查询的默认范围某个特定的版本获得的实体,您可以添加额外的谓词来返回类型的结果。

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

以相同的假设和以前一样,在修订版1创建了一个事实,另一个在修订版2,这将返回一个包含在版本2