Как сохранить сущности (или их ассоциации), привязанные к текущему контексту персистентности, к нескольким запросам (используя Wicket & JPA)?

Я работаю над веб-приложением на основе Wicket на Java EE.

Я пытаюсь найти способ гарантировать, что любые объекты, используемые в качестве объектов модели, всегда привязаны к текущему EntityManager, прежде чем Wicket попытается отобразить любые компоненты. Таким образом, когда компоненты захватывают данные из своей модели, данные могут быть лениво загружены сущностью по мере необходимости.

Здесь есть много обучающих программ и некоторые сообщения здесь, ссылаясь на LoadableDetachableModels (LDM) в качестве решения. Это сработало для нас, когда нам не нужно сохранять какие-либо промежуточные запросы. В этих случаях, всякий раз, когда страница отображается, LDM загружает самую последнюю версию требуемого объекта из базы данных.

Тем не менее, бывают случаи, когда пользователю необходимо редактировать данные в форме состояния через несколько шагов, прежде чем она сохранит данные, поэтому модели необходимо сохранить объект в состоянии "несохраненного". LDM эффективно уничтожит изменения пользователя на каждом шаге.

До сих пор мы использовали модель, которая при необходимости объединяет объект с контекстом персистентности. Вот упрощенная версия:

public final class DetachableMergingModel<E extends Identifiable> implements IModel<E> {

    private E entity;
    private boolean attached = false;

    public DetachableMergingModel(E entity) {
        this.entity = entity;
    }

    @Override
    public E getObject() {
        if (!attached) {
            attached = true;
            // Non-transactional method merges entity with persistence context 
            // but does not flush any data to database
            entity = getRepository().merge(entity);
            }
        }
        return entity;
    }

    @Override
    public void setObject(E entity) {
        this.entity = entity;
    }

    @Override
    public void detach() {
        // This ensures that the next call to getObject() will merge the entity with 
        // the persistence context
        attached = false;
    }
    /* ... */
}

Наш EntityManager вводится GlassFish, и он охватывает весь запрос сервлета, поэтому, когда объект привязан к контексту персистентности, он будет оставаться прикрепленным до тех пор, пока страница не будет отображаться.

В приведенной выше модели рассматриваются ситуации, когда объект уже сохраняется и только что редактируется. Всякий раз, когда компонент на странице вызывает getObject() в этой модели, модель объединяет объект с контекстом персистентности, и мы можем перемещаться по всему объектно-ориентированному объекту без металирования любых LazyInitializationExceptions.

Однако в ситуации, когда объект является новым и не был сохранен, мы не можем использовать эту модель, потому что сущность еще не готова к объединению. Это часто бывает, когда пользователь создает новый объект и все равно должен заполнить его значениями через форму. В этом случае мы хотим иметь такую ​​же свободу навигации по объектно-ориентированному объекту (поскольку некоторые ассоциации уже установлены, например родительский объект), не опасаясь исключения LazyInitializationException.

Аналогичное решение описывается здесь (вариант № 3), но оно не распространяется на прецедентный вариант "нового объекта", описанный выше.

Кто-нибудь сталкивался с этим прецедентом? Как вы его решили? Есть ли лучший способ интегрировать Wicket с JPA, чем с помощью пользовательских реализаций IModel?

Ответ 1

В таких случаях я обычно создаю DTO, сохраняя все данные, необходимые для создания объекта. Если вам нужно обратиться к существующим объектам - передайте их формам/панелям в виде отдельных моделей. Когда форма отправлена, вы можете:

  • выполнить проверку
  • создать новый объект из DTO, который был отредактирован
  • вводят ссылки на другие объекты, которые вы сохранили в этих отдельных моделях LDM.
  • сохранить объект.

Это немного хлопот, но на самом деле работает.

Беседы, охватывающие несколько запросов, недоступны в чистой калитки и, вероятно, никогда не будут - это не область калитки.

Шов поддерживает длинные разговоры и поддерживает калитку (я никогда не использовал шов - я не могу советовать вам об этом).

Ответ 2

Кажется, что это был старый пост.

Я надеюсь, что это поможет некоторым другим:

Во-первых: Ваш LDM немного бесполезен, поскольку свойство entity не является временным. Поэтому ваш объект сериализуется в вашем хранилище сеансов, и это не означает значение LDM. Он должен минимизировать размер сериализации любых modeldata.

Во-вторых: Ваша проблема не является реальной проблемой, потому что вам нужно, это то, что у вас уже есть: Вы хотите подготовить Entity на нескольких страницах, чтобы быть окончательно сохранены в вашей базе данных (какой-то мастер или так..). Теперь, когда ваш LDM полностью сериализуется в хранилище сеансов между запросами клиента, ваша сущность и отредактированные данные выдерживают несколько запросов, нет необходимости в слиянии. Как только ваш мастер будет закончен, вы просто сохраняете объект дыры. До того, как сущность находится в конечном состоянии, нет смысла сохранять что-либо (хотя оно выживает по запросам в вашем хранилище сеансов).

Вам даже не нужен LDM для такого рода funcionality.

Просто укажите объект как параметр на следующую страницу, где пользователь может выполнить свои данные.

Надеюсь, вы уже решили эту проблему.