users@glassfish.java.net

Re: persist() and merge() and queries: what affects persistence context?

From: Witold Szczerba <pljosh.mail_at_gmail.com>
Date: Tue, 17 Jun 2008 22:55:54 +0200

You must, maybe once again, read the EJB3/JPA spec, because what you
do is simply said... wrong:
em.contains(Object) - after Java EE5 API: "Check if the instance
belongs to the current persistence context."

It has nothing to do with existence of that entity in database, it
just checks if the entity is managed or not. You must know, when a
persistence context is closed, all managed entity objects become
detached and are unmanaged. This is the case, as your object, which
just arrived from the outer space (your client application sent it to
your session bean), cannot be, by any means, managed by the entity
manager. More than that, your entities dose not really have to travel
across the universe in order to became unmanaged, you can control that
using trasnactions, for example (transaction-scoped persistence
context), and as Mariana said, there are stateful session beans, which
can be configured to operate in extended persistence context, but this
is the other story.

I was walking the same path as you are now (but at the very beginning,
I bought a book about EJB3 and saved countless hours of trying wrong
things by myself) - and what I can suggest you is: do not worry about
em.persist and em.merge, just use the #merge method - it works
perfectly well with brand new entities. The result of #merge method is
the managed entity, does not matter if it exists already in database
or not. All you have to worry about when using #merge is not to
forget, that it does nothing with the parameter. You must abandon that
object as soon as you get your managed entity. Best what you can do is
to assign the returned object into same variable you previously used
for the unmanaged entity. This is not the case with #persist, as the
latter actually modify the same object you passed in.

One more tip: if you are developing anything bigger than just a
extended hello world application with remote client, you will sooner
or later abandon the idea of using detached entities as data transfer
objects. As I said, I have already ate that cake long time ago, and
the entity objects did not work well. What I can suggest you is to
create, in parallel, data transfer objects. Imagine you have entity
like person, which contains reference to List<Company> entity, where
each company entity can have up to whatever number of properties and
other persons, where each person can have many other companies....
When you ask entityManager to give you one person, it can read that
person or that person with list of companies. When you call method on
the one of that company, and the data was not loaded - the EM will
load it under the hood, because it manages the entities which means it
can intercept your calls on that objects and do whatever it takes to
make your person.getCompanies().get(0) work, but when you are
detaching entity and even more - serializing them, they will be
frozen. You will be actually unable to easily control how many data
should be serialized, you will face lot of troubles with exceptions
thrown by your client when it will try to dig into the data, you will
face big performance problems with too big objects being serialized,
etc... Your data transfer objects will be totally under your control,
it will be up to you to decide what data should the contain. If you
have form with person and table with 4 columns with companies of that
person, you will be happy to be able to model PersonDTO class, which
will contains nothing more (and nothing less!!!) that what you really
need. That would be enough for each CompanyDTO (or CompanyMiniDTO) to
contains only id, version, name and something more with much more
properties left empty (or just not to include them in miniDTO at all),
and when user will decide to see details, you can ask your server to
load full CompanyDTO object and open dedicated form for that...

Regards,
Witold Szczerba

2008/6/17 <glassfish_at_javadesktop.org>:
> I am still humbly thick and slow when it comes to figuring out just when to call merge() vs. persist().
>
> I am working with detached entities in an EJB3 application.
>
> The cycle that is giving me trouble goes like this:
> 1. EntityManager runs a SELECT query like this: SELECT p FROM Person p
> 2. These objects/entities get shipped over the wire to my fat client.
> 3. The fat client navigates around, etc.
> 4. The fat client ultimately selects one such entity, and calls a stateless session bean that, on its behalf, asks the EntityManager to "save" the (quite possibly modified) entity.
> 5. Laird gets confused. First, Laird tries to see if the entityManager already knows about the entity via a contains() call. The entityManager says no, never seen this item before, even though the entity manager is the one who saved it many moons ago, and, more relevantly, is the one who just loaded it up as a result of the query.
> 6. So Laird's persist() statement fires instead of the merge() statement, and Laird's code blows up, because of course the Person entity in question [i]has[/i] been persisted before with its current ID, so an EntityExistsException is thrown.
>
> So that tells me that entities returned by a query are not placed into the persistence context on their way "out". I suppose this makes sense.
>
> But [i]that[/i] tells me that I shouldn't decide whether to call persist() or merge() based on an EntityManager#contains() call, because the entity in question I'm asking the entityManager about could simply be a persistent entity that for whatever reason just isn't in the EntityManager's persistence context yet.
>
> And [i]that[/i] makes me wonder: what is the best failsafe way to ask the entityManager if it has ever seen a detached entity before? Or is the best approach to try to slam a persist() home, catch the exception, and then try a merge() (ick, yuck, I hope not)?
>
> Thanks,
> Laird
> [Message sent by forum member 'ljnelson' (ljnelson)]
>
> http://forums.java.net/jive/thread.jspa?messageID=280756
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: users-help_at_glassfish.dev.java.net
>
>