File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Object Relational Mapping and the fly likes How to add JPA ManyToMany records? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Databases » Object Relational Mapping
Bookmark "How to add JPA ManyToMany records?" Watch "How to add JPA ManyToMany records?" New topic
Author

How to add JPA ManyToMany records?

Jack Bush
Ranch Hand

Joined: Oct 20, 2006
Posts: 235
Hi All,

I would like to find out how to add records to JPA ManyToMany relationship tables. Below are the code snippets for each Java EE 5 components so far:

These createCustomer() methods resulted in multiple identical telephone numbers but I am looking for a unique normalize record in both tables.

I am running JDK1.6.0_17, GF2.1 on Windows XP.

Please advice on how this approach could be achieved. There are a few examples available but none specific to this requirement.

Any assistance would be much appreciated.

Thanks in advance,

Jack

James Sutherland
Ranch Hand

Joined: Oct 01, 2007
Posts: 553
If you want the same phone number, then you need to use the same one, not a new instance. Generally you would need to query it.

If the EJB is a remote bean, then you would need to first find the phone number and call merge in the create customer instead of persist.

In general, objects like a phone number are normally not worth sharing, and each Customer would have a OneToMany to a dependent set of phone numbers.




TopLink : EclipseLink : Book:Java Persistence : Blog:Java Persistence Performance
Jack Bush
Ranch Hand

Joined: Oct 20, 2006
Posts: 235
Hi James,

Thanks for responding to this threat.

JS wrote:
> If you want the same phone number, then you need to use the same one, not a new instance. Generally
you would need to query it.

> If the EJB is a remote bean, then you would need to first find the phone number and call merge in the
create customer instead of persist.

Good suggestion but I need 2 clarification due to lack of experience in JPA:

( i ) Currently, there is only the following CustomerBean to service Customer object:



Are you suggesting that I should create the following TelephoneBean in order to determine whether a telephone number has been added using its findTelephone():


( i )My dilemma is how to link the telephone_id returned from findTelephone(String telephone) to a new Customer instance. Any idea on how this could be achieved?

( ii ) At the same time, would updateTelephone(Telephone telephone) be able to merge current telephone number with existing record even though this step does not appears to be necessary, unless it will also link the uniquely merged telephone record with newly created Customer entity?

( iii ) Lastly, would by adding existing telephone as suggested with the following statements correctly link the same telephone record, created earlier to both wife & son with using merge() in updateTelephone method:


JS wrote:
> In general, objects like a phone number are normally not worth sharing, and each Customer would have a OneToMany to a dependent set of phone numbers.

Fair enough. This ManyToMany Customer Telephone relational model used is meant to as an example only, but the actual data used in my application is critical that must be stored in a separate secondary table.

Again, your advice would be invaluable to coming up with best simple working solution.

Thanks again,

Jack
Jack Bush
Ranch Hand

Joined: Oct 20, 2006
Posts: 235
Hi James,

Please excuse my midnight typing error for having entered Hotel object as opposed to Telephone in CustomerBean . Below are the code snippets for CustomerBean and TelephoneBean:


Which object would you suggest to merge? The Customer or Telephone? More importantly, will it associate the Telephone record found with a new Customer object?

Thanks,

Jack
James Sutherland
Ranch Hand

Joined: Oct 01, 2007
Posts: 553
A few things,

1 - I would still recommend making the Telephone a dependent part of the Customer, have a OneToMany, and don't worry about trying to share phone numbers.

2 - If you want to share phone numbers, creating the Telephone SessionBean is correct, you will need to use the findTelephone() to get the existing Telephone, and assign it to the Customer object before insert/updating it.

3 - For Customer your insert() must use merge() not persist, as the telephone may need to be merged if it is existing (merge works for both new and existing objects)

4 - So find a Telephone by name just use, "Select t from Telephone t where t.number = :number"

5 - Using the name and dob for the CustomPK is a very bad design, generate an Id instead. (what if there name changes?)

Jack Bush
Ranch Hand

Joined: Oct 20, 2006
Posts: 235
Hi James,

The first attempt to implement your suggestion 1, 3 and 4 with the following code changes:


However, this change has resulted in the following exception:

com.sun.enterprise.appclient.MainWithModuleSupport <init>
WARNING: ACC003: Application threw an exception.
javax.ejb.EJBException: nested exception is: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.RemoteException: null; nested exception is:
java.lang.IllegalStateException: Query argument number not found in the list of parameters provided during query execution.
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.RemoteException: null; nested exception is:
java.lang.IllegalStateException: Query argument number not found in the list of parameters provided during query execution.
at com.sun.corba.ee.impl.javax.rmi.CORBA.Util.mapSystemException(Util.java:243)
Likewise, GF 2.1 server log showed similar error exception:

EJB5018: An exception was thrown during an ejb invocation on [TelephoneBean]
javax.ejb.EJBException
at com.sun.ejb.containers.BaseContainer.processSystemException(BaseContainer.java:3894)
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:3794)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:3596)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1379)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1316)
at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(EJBObjectInvocationHandler.java:210)
at com.sun.ejb.containers.EJBObjectInvocationHandlerDelegate.invoke(EJBObjectInvocationHandlerDelegate.java:117)
at $Proxy47.findHotel(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:154)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:687)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:227)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1846)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1706)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:1088)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:223)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:806)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.dispatch(CorbaMessageMediatorImpl.java:563)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.doWork(CorbaMessageMediatorImpl.java:2567)
at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)
Caused by: java.lang.IllegalStateException: Query argument number not found in the list of parameters provided during query execution.
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.processParameters(EJBQueryImpl.java:559)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.executeReadQuery(EJBQueryImpl.java:329)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.getResultList(EJBQueryImpl.java:478)
at ejb.TelephoneBean.findTelephone(TelephoneBean.java:35)
The second attempt below used example from a recent EJB (JBoss) exercise when using createQuery:



However, this approach produced other communication errors that I will ignore for the moment. As a result of different version/syntax around, could I ask if you could provide the correct code for .findTelephone()?

Lastly, suggestion 5 is correct but once again I am simply using name and dob for CustomPK as an example in this threat only. Good advice nevertheless.

Thanks again,

Jack
James Sutherland
Ranch Hand

Joined: Oct 01, 2007
Posts: 553
"FROM Telephone t where t.number = :number" is not valid JPQL, you need a select clause.

Jack Bush
Ranch Hand

Joined: Oct 20, 2006
Posts: 235
Hi James,

There has been a significant reduction on the number of Telephone duplicate records added from 6 to 2 after having implemented all the above suggestions except number 3, since the use of Customer.merge() has resulted in 6 records been created again. However, I am still puzzled as to why the second Telephone record was created in the first place even though the debug statements (System.out.println) displayed only a single Customer.create(Telephone) line.

The same duplicate Telephone records exist whether a OneToMany (Unidirectional) or ManyToMany (bi-directional) JPA relational Model is used. Below are the code snippets of both ImportCustomerApplicationClient.java and TelephoneBean.java records:


Any idea on how I could further diagnose where the remaining duplicate Telephone record, and why Customer.persist(Telephone) got better result than Customer.merge(Telephone)?

Thanks a lot,

Jack
Jack Bush
Ranch Hand

Joined: Oct 20, 2006
Posts: 235
Sorry James,

Yet another typing error. Here is the correct Telephone.java:


Thanks,

Jack
 
Don't get me started about those stupid light bulbs.
 
subject: How to add JPA ManyToMany records?
 
Similar Threads
How to link existing record from database table in ManyToMany Uni-directional relationship
JPA CascadeType enquiry
Cascade Type problem
@ManyToOne & @JoinColumn
How to avoid duplicate inserts in JPA HQL (EJB 3.0 - Java EE 5)