Hi,
Please don't hesitate to point out if any of my logic is flawed :-)
I'd like to hear some thoughts about the best way to deal with entities and
persistence from an application client. As far as I can tell, there are two
possible strategies:
Strategy 1 - Local EntityManager
I can define a PersistenceUnit and have the ACC inject an EntityManagerFactory
by adding the following to my main application class:
> @PersistenceUnit(name = "jptech_punit")
> private static EntityManagerFactory emf;
I can then create an EntityManager using:
> em = emf.createEntityManager();
I can then use that EntityManager for all persistence related operations
relating to my Entity classes.
Strategy 2 - Remote facades with detached entities
I can create a remote interface that acts as a facade for persistence operations:
> @Remote
> public interface DataAccessRemote {
> public void create(Object entity);
> public Object retrieve(Class classType, int uniqueId);
> public boolean update(Object entity);
> public boolean delete(Object entity);
> }
and a matching implementation in my EJB module:
> @Stateless(name = "ejb/DataAccessBean")
> public class DataAccessBean implements DataAccessRemote {
> @PersistenceContext
> private EntityManager em;
>
> // implementation here
> }
Then in my application client, I obtain a reference to the the DataAccessBean
(facade):
> INITIAL_CONTEXT = new InitialContext();
> Object ref = INITIAL_CONTEXT.lookup("java:comp/env/ejb/DataAccessBean");
> dataAccessBean = (DataAccessBean) PortableRemoteObject.narrow(ref, DataAccessRemote.class);
and use the facade to execute my persistence operations. This method involves
moving detached entities back and forth across the network.
I can make a few observations about each strategy:
Strategy 1
It works quite well. The ACC deals with a lot of the (configuration)
complexity. All of the @Id fields in my @Entity beans get updated
automatically, regardless of cascading. Determining if an Entity is new is a
simple call to EntityManager.contains(Object entity).
However, since the EntityManager connects to and interacts with the database
directly, there's the potential to end up with several EntityManager[s]; one for
each application client and one (or more?) on the server.
Assume there is a web service querying data in a manner similar to what I
described in 'Strategy 2'. Entities managed by the server side EntityManager
could become outdated as application clients update the database.
Strategy 2
This also works ok, with one exception. When the application client is dealing
with a (newly created) detached entity and persists that entity via the
'create(Object entity)' method of the DataAccessRemote interface, the detached
copy of the entity needs to have its @Id field updated manually. It's also
necessary to update the @Id field of any child entities that have a CascadeType
of PERSIST or ALL.
Once you start dealing with trying to keep all of the entity @Id fields updated,
this strategy becomes a lot more hassle than the first, but has the advantage of
ensuring that entities managed by the server side EntityManager are no outdated.
I also don't know how well this strategy would handle entities with a
CascadeType of ALL.
Assume I had an Author (myAuthor) entity that contained a Collection of Book
entites using CascadeType.ALL. What would happen if the Author contained 1000
Book entities, I updated a 'name' field for the Author and called the
update(myAuthor) method of my DataAccessRemote interface? Would the Author plus
all 1000 Book entites be serialized and moved across the network so the server
side EntityManager can determine what needs to be updated?
I hope I've described things well enough to make it understandable. I don't
really have a question, rather I'm interested in hearing how others have been
dealing with entities and persistence in application clients. I've done a ton
of reading, but can't really find a 'definitive' way of writing an EE
application (rich) client.
Any feedback that specifically related to (optimistic) locking or security would
really interest me.
Thanks in advance for your time,
Ryan