映射到具有 JPA 注释的实体的旧版本

Mapping to an older revision of an entity with JPA annotations

我最近发现了用于审计的 envers,并且已经能够成功地使用它来跟踪修订并使用 @Audited 注释和 AuditReader 获取它们。现在,我想要实现的是将映射保留到已审计实体的修订版而不是最新修订版。

快速示例:

假设我有一个曲奇食谱,我用它来批量制作曲奇(下面 类 的伪 类)。每个食谱都有一个要遵循的说明列表,这样做会创建一个批次:

@Audited
@Table(name="recipes")
class CookieRecipe {
    @OneToMany(mappedBy="recipe")
    private List<RecipeStep> steps;

    private void addStep(String instruction) {
        steps.add(new RecipeStep(instruction));
    }
}

@Table(name="batches")
class CookieBatch {
    @ManyToOne
    @JoinColumn(...)
    private CookieRecipe recipe;
}

@Audited
@Table(name="recipe_step")
class RecipeStep {

    @Column
    private String instruction;

    @ManyToOne
    @JoinColumn(...)
    private CookieRecipe recipe;

    private RecipeStep(String instruction) {
        this.instruction = instruction;
    }
}

现在,假设我有这个 Cookie 食谱:

CookieRecipe recipe = new CookieRecipe();
recipe.addStep("Make the dough");
recipe.addStep("Place on pan");
recipe.addStep("Bake at 400F for 20 minutes");
entityManager.persist(recipe);

我将使用这个食谱制作我的第一批饼干:

CookieBatch batch = new CookieBatch(recipe);
entityManager.persist(batch);

如果我想将配方更改为 375F 而不是 400F,这将创建 CookieRecipe 的修订版 2,这正是我所期望和想要的。但是,我希望我已经创建的批次指向 CookieRecipe 的修订版 1。目前,如果我获取我已经使用其 ID 创建的 CookieBatch,则对 CookieRecipe 的引用最终成为最新修订版(带有 375F 的版本)。

这是我可以使用 envers 完成的事情吗?

我建议对 CookieBatch 进行审计,并在 CookieBatchCookieRecipe 之间保持双向关系。这样,Envers 就可以正确地从任何一方查询合适的版本。

也就是说,将以下内容添加到CookieRecipe

@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL)
private List<CookieRecipeBatch> batches = new ArrayList<>();

然后您可以使用以下循环获取适当的版本化数据:

AuditReader reader = AuditReaderFactory.get( session );
for ( Number revision : reader.getRevisions(CookieRecipe.class, recipeId ) ) {
  CookieRecipe recipe = reader.find( CookieRecipe.class, recipeId, revision );
  // recipe.getSteps() - contains all steps with revision number <= revision
  // recipe.getBatches() - contains all batches with revision number <= revision
}

以上应该会在特定修订版中为您提供 CookieRecipe,其中包含适当的批处理和步骤快照。

我相信您唯一的方法是在 CookieBatch 中保留 recipeIdrecipeRevisionNumber 字段,然后自己加载一个 CookieRecipe 对象。

@Table(name="batches")
class CookieBatch {

    @Column(...)
    Long recipeId;

    @Column(...)
    Long recipeRevisionNumber;

    @Transient
    private CookieRecipe recipe;

    @PostLoad
    public void loadRecipe()
    {
        // Load a cookie recipe via audit criteria
    }
}

审核标准很容易理解,请查看此示例:

Hibernate Envers get revisions for criteria

以及所有内容的文档:

http://docs.jboss.org/envers/docs/