I may have misunderstood your current issue.  It seems you are able to get a
successful response if you call the getContactList().size() method before
returning from your method.  If that is the case then adding the
@TransactionAttribute will probably not change anything.

The issue you are having is really common and happens everywhere you use JPA
entities as objects that you pass across transaction boundaries.  As soon as
the JPA entity is detached, which happens when the transaction commits at
the end of your method, you can't automatically load lazy-loaded attributes. 
Because your method is a webservice operation, the response gets marshalled
by JAXB into XML which is when the getContactList() call would be happening
after the transaction has committed.  The same issue would also happen if
you got a Customer entity in a servlet within a transaction and then passed
it to a JSP page for rendering and that JSP page tried to call the
getCustomerList method.  

There are several ways of solving this problem.  One way in web applications
is to use a servlet filter to start and end the transaction so that the JSP
page rendering would happen within the same transaction that the Customer
entity was retrieved from the database.  In this case, the Customer entity
is not detached and so the JSP page call to getContactList() would cause the
EntityManager to retrieve the data from the database.  I'm not sure if there
is a similar mechanism you could use for a webservice.  Perhaps there is
some interceptor you could use around the getCustomer method that could
start and commit the transaction after the XML serialization has occurred.

Another way is to design your app so you don't use JPA entities as data
transfer objects (DTOs).  Create another package of dto java beans that are
used explicitely for this purpose.  Then create stateless ejbs that populate
DTOs from your JPA entities within a transaction.  The DTO object would then
be returned from your webservice and be guaranteed to have all the state 
already loaded.  Although this way sounds like alot more work and i may get
flamed for suggesting it, i personally prefer this approach because it takes
away the uncertainty about what is or isn't loaded that you always get with
JPA entities.

Another way is to do as you are currently doing and make sure you call
methods that you think are going to be called on the Customer object after
you return it.  As you have said, this way is not great because you have to
guess what lazy loaded attributes the caller of your method is interested
in.  If you don't like using the method calls to load the lazy-loaded
attributes, an alternative is to create a JPA query using the "FETCH"
keyword to perform an eager fetch of the lazy loaded attributes.

eg.  entityManger.createQuery("SELECT c FROM Customer c LEFT JOIN FETCH
c.contactList WHERE c.id = :id").setParameter("id",
customerId).getSingleResult();

--
View this message in context: 
http://openejb.979440.n4.nabble.com/CMP-failed-with-3-layered-Object-structure-tp4655311p4655609.html
Sent from the OpenEJB User mailing list archive at Nabble.com.

Reply via email to