2012-02-03 4 views
5

J'ai une application sandbox Seam 3 utilisant JBoss 7, Hibernate comme implémentation JPA par défaut et JSF comme frontal Web.JPA/Hibernate n'émet aucune mise à jour lors de la validation dans un environnement EJB/Seam

J'ai le problème, que le SQL UPDATE est avalé par défaut.

Mon stateful EJB portée de conversation maintient une longue portée a été définie EntityManager et une entité, les transactions gérées par conteneurs (Oblige les nouveaux)

  1. Le EntityManager obtient injecté
  2. L'EJB utilise l'EM pour charger l'entité et conserve dans un champ
  3. application JSF accède à l'EJB et son entité, modifie un champ de chaîne
  4. application JSF calles méthode « Enregistrer » dans EJB
  5. dans save() Je vérifie, si le champ Entities a été changé -> il a été changé correctement
  6. Je ne fais rien de plus, le conteneur valide la transaction après que save() soit fini.
  7. Problème: Aucune mise à jour SQL n'est effectuée sur le DB.

Si je transmets save() par:

a) entityManager.contains (entité) UPDATE est exécutée comme prévu (résultat est "vrai")

OU

b) entityManager.persist (entity) le UPDATE est exécuté comme prévu

Q: Dans la mesure où je comprends les spécifications, ni de a) ni de b) ne devraient être requises, car l'entité reste gérée pendant tout le processus. Je ne comprends pas, pourquoi a) a un effet sur la sauvegarde. Je peux imager le b) a un effet sur la sauvegarde, mais il ne devrait pas être nécessaire, devrait-il?

Toute explication est la bienvenue.

Voici mon 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"; 
    } 

} 
+0

J'ai découvert entityManager.flush() résout également le problème. Mais je ne comprends pas pourquoi cela semble nécessaire. De la spécification JPA: "Lorsque la transaction JTA valide, le fournisseur doit vider tout l'état de l'entité modifiée à la base de données ." – user1187037

+0

peut-être quelque part le FlushMode de la session d'hibernation est défini sur none? – Firo

Répondre

0

Essayez d'ajouter @Remove annotation sur les méthodes annotées par @End.

À mon avis, l'annotation @End n'entraîne pas la destruction du haricot. Le contexte de persistance est donc actif même après l'exécution de save() et son contenu ne peut pas être vidé dans la base de données.

1

Mon expérience est en grande partie avec seam-2 mais devrait être également applicable ici.

La session de conversation et JPA est découplée en couture pour la simple raison qu'une fin de conversation ne peut pas entraîner l'enregistrement de l'entité.

Par exemple, une annulation d'action sur une longue conversation en cours d'exécution mettrait fin à la conversation (car il n'y a aucune raison de maintenir la conversation plus)

Considérant que vous faites un retour en arrière sur l'annuler dans votre exemple, semblerait également logique que vous auriez besoin d'appeler un flush comme suggéré par @ user1187037 (théoriquement un commit mais je ne pense pas que c'est autorisé)

Je pense qu'il y avait peut-être une configuration que vous pouviez définir de sorte qu'elle fasse flush en fin de conversation mais je peux me tromper.

Dans tous les cas, http://javalangblog.blogspot.co.uk/2010/04/flush-mode-conversation.html semble suggérer une solution

espoir qui aide.

EDIT: Vous pouvez configurer le mode de rinçage par conversation à l'aide xml

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

et utilisant des annotations

@Begin(flushMode=COMMIT) 

Gardez à l'esprit qu'une conversation peut @End sans qu'il soit explicitement défini. Si un utilisateur est à mi-chemin de la conversation, a apporté des modifications aux entités et abandonne ensuite la conversation, il sera automatiquement fermé après un délai d'attente. Si je me souviens bien, cela entraînera des changements dans le cas ci-dessus.

Références:

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

Questions connexes