【问题标题】:Mapping to an older revision of an entity with JPA annotations使用 JPA 注释映射到实体的旧版本
【发布时间】:2017-02-11 22:44:45
【问题描述】:

我最近发现了用于审计的 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;
    }
}

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

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 不是@Audited 是故意的吗?如果是这样,我不相信有一种优雅的方式来做你想做的事情。
  • @SergeiBednar 是的,唯一的原因是一旦CookieBatch 完成,它就不会改变。所以我认为这是不必要的,因为它只会创建一个永远不会真正使用的审计表......除非我误解了这种行为。如果它导致解决方案,我不反对添加@Audited
  • 我认为您唯一的其他解决方案是保留recipeIdrecipeRevisionNumber 值,将CookieBatch 中的recipe 实体更改为@Transient,并处理查询在加载 CookieBatch 实体后,通过 envers AuditCriteria 自己制作配方。
  • @SergeiBednar 我认为这将是适合我的解决方案,介意将其作为解决方案发布吗?此外,您是否了解在持久化CookieBatch 时如何获取recipeRevisionNumber
  • 此时CookieRecipe 应该保持不变,您可以通过审核标准获得最新版本。查看此文档,它非常可靠:docs.jboss.org/envers/docs

标签: hibernate jpa hibernate-envers


【解决方案1】:

我相信您这样做的唯一方法是在您的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/

【讨论】:

    【解决方案2】:

    我建议对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,并带有适当的批处理和步骤快照。

    【讨论】:

    • 我的目标是使用批次 ID 获取 CookieBatch,并让它引用创建时使用的 CookieRecipe 的修订版。不幸的是,我不知道“适当的修订”是什么,那是缺失的数据。除非我在创建CookieBatch 时特别需要检索和存储它,就像@SergeiBednar 推荐的那样?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 2016-02-14
    • 2011-07-13
    • 2010-10-06
    • 2013-03-04
    • 1970-01-01
    相关资源
    最近更新 更多