Je n'arrive pas à essayer de conserver une entité dont l'ID est une valeur générée. Cette entité (A), au moment de la persistance, doit persister en cascade d'une autre entité (B). La relation entre A et B est OneToMany et la propriété liée à B fait partie d'une clé composite.Impossible de synchroniser l'état de la base de données avec la session
J'utilise Eclipse, JBOSS Runtime, JPA/Hibernate
Voici mon code:
Entité A:
@Entity
public class Cambios implements Serializable {
private static final long serialVersionUID = 1L;
@SequenceGenerator(name="CAMBIOS_GEN",sequenceName="CAMBIOS_SEQ",allocationSize=1)
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CAMBIOS_GEN")
@Column(name="ID_CAMBIO")
private Long idCambio;
//bi-directional many-to-one association to ObjetosCambio
@OneToMany(cascade={CascadeType.PERSIST},mappedBy="cambios")
private List<ObjetosCambio> objetosCambioList;
public Cambios() {
}
...
}
Entité B:
@Entity
@Table(name="OBJETOS_CAMBIO")
public class ObjetosCambio implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private ObjetosCambioPK id;
//bi-directional many-to-one association to Cambios
@ManyToOne
@JoinColumn(name="ID_CAMBIO", insertable=false, updatable=false)
private Cambios cambios;
//bi-directional many-to-one association to Objetos
@ManyToOne
@JoinColumn(name="ID_OBJETO", insertable=false, updatable=false)
private Objetos objetos;
public ObjetosCambio() {
}
...
Entité B PK:
@Embeddable
public class ObjetosCambioPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
@Column(name="ID_OBJETO")
private Long idObjeto;
@Column(name="ID_CAMBIO")
private Long idCambio;
public ObjetosCambioPK() {
}
Client:
public String generarCambio(){
ServiceLocator serviceLocator = null;
try {
serviceLocator = serviceLocator.getInstance();
FachadaLocal tcLocal;
tcLocal = (FachadaLocal)serviceLocator.getFacadeService("java:comp/env/negocio/Fachada");
Cambios cambio = new Cambios();
Iterator it = objetosLocal.iterator(); //OBJETOSLOCAL IS ALREADY POPULATED OUTSIDE OF THIS METHOD
List<ObjetosCambio> ocList = new ArrayList();
while (it.hasNext()){
Objetos objeto = (Objetos)it.next();
ObjetosCambio objetosCambio = new ObjetosCambio();
objetosCambio.setCambios(cambio); //AT THIS TIME THIS "CAMBIO" DOES NOT HAVE ITS ID, ITS SUPPOSED TO BE GENERATED AT PERSISTENCE TIME
ObjetosCambioPK ocPK = new ObjetosCambioPK();
ocPK.setIdObjeto(objeto.getIdObjeto());
objetosCambio.setId(ocPK);
ocList.add(objetosCambio);
}
cambio.setObjetosCambioList(ocList);
tcLocal.persistEntity(cambio);
return "exito";
} catch (NamingException e) {
// TODO
e.printStackTrace();
}
return null;
}
ERROR:
15:23:25,717 WARN [JDBCExceptionReporter] SQL Error: 1400, SQLState: 23000
15:23:25,717 ERROR [JDBCExceptionReporter] ORA-01400: no se puede realizar una inserción NULL en ("CDC"."OBJETOS_CAMBIO"."ID_CAMBIO")
15:23:25,717 WARN [JDBCExceptionReporter] SQL Error: 1400, SQLState: 23000
15:23:25,717 ERROR [JDBCExceptionReporter] ORA-01400: no se puede realizar una inserción NULL en ("CDC"."OBJETOS_CAMBIO"."ID_CAMBIO")
15:23:25,717 ERROR [AbstractFlushingEventListener] Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:504)
at com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple.beforeCompletion(SynchronizationImple.java:101)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.beforeCompletion(TwoPhaseCoordinator.java:269)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:89)
at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:177)
at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1423)
at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:137)
at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:75)
at org.jboss.aspects.tx.TxPolicy.endTransaction(TxPolicy.java:170)
at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:87)
at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:190)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.tx.NullInterceptor.invoke(NullInterceptor.java:42)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.security.Ejb3AuthenticationInterceptorv2.invoke(Ejb3AuthenticationInterceptorv2.java:186)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:41)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.BlockContainerShutdownInterceptor.invoke(BlockContainerShutdownInterceptor.java:67)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.aspects.currentinvocation.CurrentInvocationInterceptor.invoke(CurrentInvocationInterceptor.java:67)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.session.SessionSpecContainer.invoke(SessionSpecContainer.java:176)
at org.jboss.ejb3.session.SessionSpecContainer.invoke(SessionSpecContainer.java:216)
at org.jboss.ejb3.proxy.impl.handler.session.SessionProxyInvocationHandlerBase.invoke(SessionProxyInvocationHandlerBase.java:207)
at org.jboss.ejb3.proxy.impl.handler.session.SessionProxyInvocationHandlerBase.invoke(SessionProxyInvocationHandlerBase.java:164)
at $Proxy298.persistEntity(Unknown Source)
at backing.SolicitudCambio.generarCambio(SolicitudCambio.java:521)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.faces.el.MethodBindingImpl.invoke(MethodBindingImpl.java:146)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:92)
at javax.faces.component.UICommand.broadcast(UICommand.java:332)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:287)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:401)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:95)
at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:245)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:110)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:213)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:301)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Unknown Source)
Caused by: java.sql.BatchUpdateException: ORA-01400: no se puede realizar una inserción NULL en ("CDC"."OBJETOS_CAMBIO"."ID_CAMBIO")
Merci à l'avance! JM.-
J'ai essayé de mettre cambios.idCambio manuellement mais je me fais toujours la même erreur. Hibernate devrait faire une sorte de correspondance entre objetosCambioPK.idCambio et objetosCambio.cambios. Peut-être que c'est ce qui me manque ici, et je ne sais pas comment l'appliquer.
Quelqu'un?
Merci pour votre réponse, je l'ai déjà fait une fois mais c'était avec une architecture différente (EJB3, Jdeveloper, Toplink), donc je sais que cela pourrait fonctionner. À l'époque, j'utilisais l'annotation '@ IdClass' au lieu de' @ EmbeddedId', mais j'ai lu que ce n'est pas la meilleure approche de nos jours, il semble que cette @IdClass n'a été implémentée que dans Hibernate à cause de la compatibilité EJB2. En plus de cela, j'ai des problèmes avec '@ idClass' aussi ... donc je préfère continuer à essayer de trouver une solution pour celle-ci. En ce qui concerne votre conseil: – Steppen
"Je voudrais donc persister() et vider() le nouveau Cambios en premier, puis définir l'ID assigné sur la clé composite de chaque instance d'ObjetosCambio." Si je fais cela comme vous le dites, ne risquerais-je pas de laisser la base de données dans un état incohérent? (Dans le cas où une exception survient au temps de persistance 'ObjetosCambio') – Steppen
@Steppen Si une exception survient à l'heure de persistance de' ObjetosCambio', la transaction sera annulée et vous ne serez pas dans un état incohérent. –