problem with a relationship ManyToMany between entities
I have a problem with a ManyToMany relationship between entities. Adding works very well but I can't remove a Commune.
Here are my entites:
public class Tuteur implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nom;
@ManyToMany(mappedBy="tuteurs",fetch=FetchType.EAGER)
private List<Commune> communes;
...
}
public class Commune implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nomCommune;
@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name="Tuteur_Commune",joinColumns=@JoinColumn(name="Commune_Fk",
referencedColumnName="id")
,inverseJoinColumns=@JoinColumn(name="Tuteur_Fk",referencedColumnName="id"))
private List<Tuteur> tuteurs;
...}
I have this error message:
javax.faces.el.EvaluationException: javax.ejb.EJBException: Transaction aborted
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
at javax.faces.component.UICommand.broadcast(UICommand.java:315)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:775)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1267)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
at java.lang.Thread.run(Thread.java:636)
Caused by: javax.ejb.EJBException: Transaction aborted
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5046)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4805)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2004)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1955)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:198)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:84)
at $Proxy218.supprimer(Unknown Source)
at SessionTest.__EJB31_Generated__TestSession__Intf____Bean__.supprimer(Unknown Source)
at test.supprimer(test.java:66)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.sun.el.parser.AstValue.invoke(AstValue.java:234)
at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:297)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:98)
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
... 32 more
Caused by: javax.transaction.RollbackExcept开发者_StackOverflowion: Transaction marked for rollback.
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:450)
at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:837)
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5040)
... 48 more
Caused by: Exception [EclipseLink-45] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Missing mapping for field [Commune.id].
Descriptor: RelationalDescriptor(entites.Commune --> [DatabaseTable(Commune)])
at org.eclipse.persistence.exceptions.DescriptorException.missingMappingForField(DescriptorException.java:951)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.extractValueFromObjectForField(ObjectBuilder.java:1970)
at org.eclipse.persistence.mappings.ManyToManyMapping.prepareTranslationRow(ManyToManyMapping.java:931)
at org.eclipse.persistence.mappings.ManyToManyMapping.earlyPreDelete(ManyToManyMapping.java:135)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1374)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:547)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1508)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.issueSQLbeforeCompletion(UnitOfWorkImpl.java:3128)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitOfWork.java:268)
at org.eclipse.persistence.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:157)
at org.eclipse.persistence.transaction.JTASynchronizationListener.beforeCompletion(JTASynchronizationListener.java:68)
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:412)
... 50 more
You can't delete a Commune when it is linked to one or more Tuteur records due to foreign key constraints. You must either use one of the Cascade options to have dependent records deleted (although this is unusual for many-to-many relationships as in your case), or you must write logic that breaks the relationship.
So I'm guessing in your case, the correct solution would be to first clear the relationship between the Commune instance and all referenced Tuteur instances, then delete the Commune instance.
You can either do this programmatically like shown below:
for (Tuteur tuteur in commune.tuteurs) {
tuteur.getCommunes().remove(commune);
entityManager.persist(tuteur);
}
commune.getTuteurs().clear();
entityManager.persist(commune);
entityManager.remove(commune);
Or with a couple of JPQL update statements.
Edit: I re-read your stack trace, which contains the following root cause:
Caused by: Exception [EclipseLink-45] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Missing mapping for field [Commune.id].
Descriptor: RelationalDescriptor(entites.Commune --> [DatabaseTable(Commune)])
Now, in my experience EclipseLink sometimes throw misleading or confusing exceptions.
I looked at your @JoinTable
declaration and I did notice that in your particular case, the referenceColumnName
option can be left out, since your foreign key is the @Id
column of the target table in both directions. I don't think that is the cause of the problem, but you might want to try that anyway.
Another option to try is to simply let JPA and EclipseLink define the join table. You do that by leaving out the @JoinTable
declaration altogether. Unless you have a specific reason for manually declaring the join table, this is the way to go anyway. Remember, a lot of the improvements in EJB 3.0 have to do with convention over control in order to cut down on the boiler plate code and configuration requirements.
精彩评论