2012-01-31 7 views
10

J'ai une entité utilisateur:EntityManager.merge ne fait rien

@Entity 
@Table(name = "bi_user") 
@SequenceGenerator(name = "USER_SEQ_GEN", sequenceName = "USER_SEQUENCE") 
public class User 
     extends DataObjectAbstract<Long> 
{ 
    private static final long serialVersionUID = -7870157016168718980L; 

    /** 
    * key for this instance. Should be managed by JPA provider. 
    */ 
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ_GEN") 
    private Long key; 

    /** 
    * Username the user will use to login. This should be an email address 
    */ 
    @Column(nullable=false, unique=true) 
    private String username; 

    // etc. other columns and getters/setters 
} 

Où DataObjectAbstract est un @MappedSuperClass simple qui a une version JPA et égale/définition hashcode.

J'ai une classe dao de base qui ressemble à ceci

public abstract class BaseDaoAbstract<T extends DataObject<K>, K extends Serializable> 
     implements BaseDao<T, K> 
{ 

    @PersistenceContext 
    private EntityManager em; 

    /** 
    * Save a new entity. If the entity has already been persisted, then merge 
    * should be called instead. 
    * 
    * @param entity The transient entity to be saved. 
    * @return The persisted transient entity. 
    */ 
    @Transactional 
    public T persist(T entity) 
    { 
     em.persist(entity); 
     return entity; 
    } 

    /** 
    * merge the changes in this detached object into the current persistent 
    * context and write through to the database. This should be called to save 
    * entities that already exist in the database. 
    * 
    * @param entity The entity to be merged 
    * @return The merged entity. 
    */ 
    @Transactional 
    public T merge(T entity) 
    { 
     return em.merge(entity); 
    } 

    // other methods like persist, delete, refresh, findByKey that all delegate to em. 
} 

J'ai défini le filtre OpenEntityManagerInView dans web.xml comme suit

<filter> 
    <filter-name>openEntityManagerInViewFilter</filter-name> 
    <filter-class> 
     org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter 
    </filter-class> 
    <init-param> 
     <param-name>entityManagerFactoryBeanName</param-name> 
     <param-value>biEmf</param-value> 
    </init-param> 
</filter> 

<filter-mapping> 
    <filter-name>openEntityManagerInViewFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

I récemment mis à jour à EclipseLink 2.3.2 et printemps 3.1 et converti à partir de proxies CGLIB à Load Time Weaving avec aspectJ pour Spring mais je n'ai pas configuré LTW pour eclipselink.

Le problème est dans ce code qui réside dans un Spring ApplicationListener, voir les commentaires.

 User user = userService.findByKey(userDetails.getKey()); 

     // THIS MERGE NEVER WRITES THROUGH TO THE DATABASE. 
     // THIS DOESN'T WORK AS PERSIST EITHER 
     user = userService.merge(user.loginSuccess()); 

user.loginSuccess définit juste quelques champs et retourne this Je suis certain qu'il devient dans le code parce que je reçois des déclarations autour de vous connecter et je peux mettre un point d'arrêt et de marcher à travers elle. Mon journal postgres ne montre aucun trafic accédant à postgres pour la fusion. Je sauve d'autres choses partout sans problème, y compris les utilisateurs dans un autre endroit quand ils changent leur mot de passe, et je sais que ce code a l'habitude de fonctionner. Y a-t-il quelque chose qui cloche ici? Est-ce que j'utilise le OpenEntityManagerInViewFilter de manière incorrecte? Devrais-je être dans une méthode @Transactional pour que les entités soient considérées comme gérées? Toute aide est appréciée.

Mise à jour J'ai essayé le flush comme suggéré par prajeesh. Voici le code

@Transactional 
public T merge(T entity) 
{ 
    entity = em.merge(entity); 
    em.flush(); 
    return entity; 
} 

dans une classe en com.bi.data. J'ai dans mon fichier de configuration app printemps

<context:component-scan base-package="com.bi.controller,com.bi.data,com.bi.web" /> 

Dans ma configuration de printemps, j'ai

<context:load-time-weaver/> 
<tx:annotation-driven mode="aspectj"/>  

avec un aop.xml qui ressemble à ceci:

<aspectj> 
    <weaver> 
     <!-- only weave classes in our application-specific packages --> 
     <include within="com.bi..*"/> 
    </weaver> 
</aspectj> 

et je suis un

javax.persistence.TransactionRequiredException: 
Exception Description: No transaction is currently active 

Quelque chose est évidemment mal configuré, mais quoi?

Mise à jour 2: Je Reconvertit mes changements pour permettre le tissage de temps de chargement et maintenant la fusion passe par avec ou sans chasse d'eau, mais je ne comprends toujours pas ce que le problème est avec LTW ...

+0

Il semble que vous ayez configuré la transaction correctement. Peut-être inclure votre persistence.xml, assurez-vous que vous utilisez RESOURCE_LOCAL. Activer la journalisation sur les plus fins pour voir ce qui se passe. – James

+0

Merci pour les idées de James. Je vais y jeter un coup d'œil après le travail. Je suis à peu près certain que nous utilisons RESOURCE_LOCAL parce que nous courons dans Tomcat, donc jamais JTA. – digitaljoel

+0

Avez-vous essayé d'ajouter propagation = Propagation.REQUIRED à l'annotation @Transactional? –

Répondre

12

Essayez le em.flush() également après le em.merge(). Parfois, le EntityManager garde juste les changements pour la mise à jour plus tard.

+1

cela n'a pas fonctionné pour moi – vicky

1

Où est le transaction.begin() et transaction.end() méthodes? Dans RESOURCE_LOCAL vous devez gérer la transaction et non l'application ...

+0

Une autre possibilité est la transaction est en lecture seule. – okwap

0

Vérifiez s'il y a la ligne suivante dans votre fichier de configuration Spring: Cela permet le support d'annotation @Transactional, et assurez-vous que le mode = » proxy ", not mode =" aspectj " est défini

+0

Le lien ne fonctionne plus. –

2

EntityManager autocommit est false. S'il vous plaît utiliser la transaction comme ci-dessous;

EntityManager em = null; 
EntityTransaction t = null; 
try { 
    em = emf.createEntityManager(); 
    t = em.getTransaction(); 
    t.begin(); 
    em.merge(myTestObject); 
    t.commit(); 
} catch (Exception e) { 
    t.rollback(); 
    throw new RuntimeException(e.getMessage()); 
}finally{ 
    if(em != null) 
     em.close(); 
} 
+0

J'utilise jpa et il n'autorise pas em.getTransaction(), – vicky

+0

Parfois, JPA ne trouve pas le fichier persistence.xml dans le chemin. Où est votre chemin persistence.xml? Si votre em est null, déplacez persistence.xml dans src/main/java/META-INF/persistence.xml – ethemsulan