Сопоставление с более старой версией объекта с аннотациями JPA

Недавно я узнал о envers для аудита и смог успешно использовать его для отслеживания изменений и получения их с помощью аннотации @Audited и AuditReader. Теперь то, что я пытаюсь достичь, - это сохранить сопоставления с проверяемой сущностью в той ревизии, в которой они были сделаны, вместо самой последней ревизии.

Быстрый пример:

Допустим, у меня есть рецепт для файлов cookie, который я использую для создания пакетов файлов cookie (псевдоклассы для классов ниже). У каждого рецепта есть список инструкций, которым нужно следовать, и при этом создается партия:

@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);

И я буду использовать этот рецепт для создания своей первой партии файлов cookie:

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

Если бы я хотел изменить рецепт, чтобы сказать, например, 375F вместо 400F, это создаст ревизию 2 CookieRecipe, чего я ожидаю и хочу. Однако я хочу, чтобы уже созданная мною партия указывала на ревизию 1 файла CookieRecipe. В настоящее время, если я извлекаю CookieBatch, который я уже создал, используя его идентификатор, ссылка на CookieRecipe оказывается последней ревизией (с 375F).

Могу ли я этого добиться с помощью envers?


person cklab    schedule 03.10.2016    source источник
comment
CookieBatch не быть @Audited намеренно? Если так, то я не верю, что есть элегантный способ делать то, что вы пытаетесь сделать.   -  person SergeiBednar    schedule 04.10.2016
comment
@SergeiBednar Да, единственная причина в том, что после завершения CookieBatch он не меняется. Поэтому я решил, что в этом нет необходимости, поскольку это просто создаст таблицу аудита, которая никогда не будет использоваться на самом деле ... если я не пойму это поведение неправильно. Я не против добавления к нему @Audited, если это приведет к решению.   -  person cklab    schedule 04.10.2016
comment
Я думаю, что ваше единственное другое решение здесь - сохранить значения recipeId и recipeRevisionNumber, изменить сущность recipe в вашем CookieBatch на @Transient и самостоятельно обрабатывать запросы рецепта через envers AuditCriteria после загрузки сущности CookieBatch.   -  person SergeiBednar    schedule 04.10.2016
comment
@SergeiBednar Я думаю, что это будет решение, которое подойдет мне, не могли бы опубликовать его как решение? Кроме того, есть ли у вас представление о том, как получить recipeRevisionNumber во время сохранения CookieBatch?   -  person cklab    schedule 06.10.2016
comment
К этому моменту CookieRecipe должен быть сохранен, и вы можете получить последнюю версию с помощью критериев аудита. Ознакомьтесь с этой документацией, она довольно солидная: docs.jboss.org/envers/docs   -  person SergeiBednar    schedule 06.10.2016


Ответы (2)


Я считаю, что ваш единственный способ сделать это - сохранить поля recipeId, recipeRevisionNumber в вашем CookieBatch и самостоятельно загрузить 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 получают изменения для критериев

и документация на все:

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

person SergeiBednar    schedule 05.10.2016

Я бы посоветовал провести аудит CookieBatch, а также поддерживать двунаправленную связь между CookieBatch и CookieRecipe. Таким образом, 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 в конкретной ревизии с соответствующими пакетными и пошаговыми снимками.

person Naros    schedule 04.10.2016
comment
Моя цель - получить CookieBatch, используя идентификатор пакета, и сделать так, чтобы он ссылался на ревизию CookieRecipe, использовавшуюся во время создания. К сожалению, я не знаю, что такое «подходящая ревизия», это недостающие данные. Если мне не нужно специально извлекать и сохранять это при создании CookieBatch, например, что рекомендует @SergeiBednar? - person cklab; 04.10.2016