JPA/Hibernate не выдает UPDATE при фиксации в среде EJB/Seam

У меня есть приложение-песочница Seam 3, использующее JBoss 7, Hibernate в качестве реализации JPA по умолчанию и JSF в качестве веб-интерфейса.

У меня проблема, что SQL UPDATE проглатывается по умолчанию.

Мой EJB с отслеживанием состояния в области диалога поддерживает EntityManager с расширенной областью действия и одну сущность, транзакции, управляемые контейнером (требуется новый)

  1. EntityManager вводится
  2. EJB использует EM для загрузки Entity и сохраняет его в поле
  3. Приложение JSF обращается к EJB и его объекту, изменяет поле String
  4. Приложение JSF вызывает метод «Сохранить» в EJB
  5. В save() я проверяю, было ли изменено поле Entities -> оно было изменено правильно
  6. Я больше ничего не делаю, контейнер фиксирует транзакцию после завершения save().
  7. Проблема: не выполняется обновление SQL для базы данных.

Если я расширим save() на:

а) entityManager.contains(entity) ОБНОВЛЕНИЕ выполняется, как и ожидалось (результат «истина»)

OR

б) entityManager.persist(entity) ОБНОВЛЕНИЕ выполняется, как и ожидалось

Q: Насколько я понимаю, спецификации ни a), ни b) не требуются, потому что сущность остается управляемой в течение всего процесса. Я не понимаю, почему а) влияет на сохранение. Я могу представить, что b) влияет на сохранение, но это не обязательно, не так ли?

Любое объяснение приветствуется.

Вот мой EJB:

@Named
@ConversationScoped
@Stateful
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class LanguageBean {

    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;
    @Inject
    private UserTransaction transaction;

    private Language value;

    @Inject
    Conversation conversation;

    public LanguageBean() {
        super();
    }

    @Begin
    public void selectLanguage(Long anId) {
        conversation.setTimeout(10 * 60 * 1000);
        if (anId != null) {
            value = em.find(Language.class, anId);
        }
    }

    @BeforeCompletion
    public void transactionComplete(){
        System.out.println("transactionComplete");
    }

    public Language getValue() {
        return value;
    }

    @Produces
    @Named
    @ConversationScoped
    public Language getLanguage() {
        return getValue();
    }

    public void setValue(Language aValue) {
        value = aValue;
    }

    @End
    public String save() {
//      displays the changed attribute:
        System.out.println("save code: "+value.getCode());

//      why is either this required:
//      boolean tempContains = em.contains(value);
//      System.out.println("managed: "+tempContains);

//      or: why is persist required:
        em.persist(value);
        return "languages?faces-redirect=true";
    }

    @End
    public String cancel() throws SystemException {
        transaction.setRollbackOnly();
        return "languages?faces-redirect=true";
    }

}

person user1187037    schedule 03.02.2012    source источник
comment
Я узнал, что entityManager.flush() также решает проблему. Но я не понимаю, почему это, кажется, требуется. Из спецификации JPA: когда транзакция JTA фиксируется, провайдер должен сбросить все измененное состояние объекта в базу данных.   -  person user1187037    schedule 03.02.2012
comment
может быть, где-то для FlushMode сеанса гибернации установлено значение none?   -  person Firo    schedule 06.02.2012


Ответы (2)


Мой опыт в основном связан со швом-2, но он должен быть в равной степени применим и здесь.

Разговор и сеанс JPA отделены друг от друга по той простой причине, что окончание разговора может не привести к сохранению объекта.

Например, действие «Отмена» в длительном разговоре завершит разговор (поскольку больше нет причин поддерживать разговор).

Учитывая, что вы выполняете откат при отмене в своем примере, также может показаться логичным, что вам нужно будет вызвать сброс, как предложено @user1187037 (теоретически фиксация, но я не думаю, что это разрешено)

Я думаю, что, возможно, была конфигурация, которую вы могли бы настроить так, чтобы она сбрасывалась в конце разговора, но я могу ошибаться.

В любом случае http://javalangblog.blogspot.co.uk/2010/04/flush-mode-conversation.html предлагает решение

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ: вы можете настроить режим сброса для каждого разговора, используя xml

<begin-conversation join="true" flush-mode="COMMIT" />

и используя аннотации

@Begin(flushMode=COMMIT)

Имейте в виду, однако, что разговор может @End без явного определения. Если пользователь находится на полпути к беседе, внес изменения в объекты, а затем отказывается от беседы, она будет автоматически закрыта по истечении тайм-аута. Если я правильно помню, это приведет к фиксации любых изменений в приведенном выше случае.

Использованная литература:

http://docs.jboss.org/seam/3/persistence/3.0.0.Alpha1/reference/en-US/html_single/#d0e249 http://docs.jboss.org/seam/3/latest/api/org/ jboss/seam/persistence/FlushModeType.html

person drone.ah    schedule 17.10.2012

Попробуйте добавить аннотацию @Remove к методам, аннотированным @End.

На мой взгляд, аннотация @End не приводит к уничтожению компонента. Таким образом, контекст сохранения активен даже после выполнения save(), и его содержимое не может быть сброшено в базу данных.

person pWoz    schedule 16.03.2012