Как сохранить сущности (или их ассоциации) подключенными к текущему контексту постоянства по нескольким запросам (используя Wicket и JPA)? - PullRequest
11 голосов
/ 16 августа 2011

Я работаю над веб-приложением на основе 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?

Ответы [ 2 ]

1 голос
/ 05 сентября 2011

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

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

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

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

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

0 голосов
/ 06 июля 2012

Кажется, что-то вроде старого сообщения ..

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

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

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

Вам даже не нужен LDM для такого рода функций..

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

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

...