>'did not touch'? i think you are referring to checking size() or isEmpty()
Yes, sometimes you even need to iterate through those lists and touch all the 
lazy loading fields of those 1:n entities if you know you need them in the 
frontend.



>It is interesting that you refer to it as a restriction. do you 

> prefer/recommend this approach, or another approach?
In those cases I'd go d' accord with Romain and suggest using DTOs.



> I think I read somewhere how size() and isEmpty() will retrieve the 

> data, but now I know, you must do this inside @EJB. right?

Yes, you can think of an @Stateless EJB as a CDI bean which has (amongst 
others) a CDI @Transactional interceptor [1] automatically applied to it. What 
happens is kind of what I show on page 31 in [2]. Simplified, but you get the 
idea I hope. 


This makes it obvious that once the method you invoke on your (outermost) EJB 
returns, then the interceptor will commit the transaction and close the 
EntityManager again. Please note that the EntityManager you get with 
@PersistenceContext is NOT a native JPA EntityManager but just a facade which 
delegates to the _real_ EM (per Thread and EJB invocation). And this 'real' EM 
will gets closed in the Transactional interceptor, which means all the entities 
loaded by it will automatically get detached in that moment. 
I hope it's clear now why lazy loading and other stuff _outside_ the EJB does 
not work as expected ;)

You should nontheless be able to change values in the entites and those changes 
must get reflected to the database if you later em.merge it inside an EJB. Oh 
btw, an error which also happens pretty often is that em.merge gets used the 
wrong way:

SomeStuff mergedAndManagedEntity = em.merge(detachedEntity);


the PARAMETER entity will NOT become managed! Only the return value is managed!


>are you recommending this for only OpenJPA users? 

> I'm using 
EclipseLink and (Apache) Derby. I think I read 

> about this before 
somewhere; is the 'optlock' part of 

> Java EE implementation or just for 
OpenJPA users?

@Version is a *very* important part of the JPA spec itself. 

I'm not sure why, but this is something which is often missing in applications.
Maybe because almost none of the JavaEE samples on the Oracle page and in 
JavaEE talks mention this and other important stuff (like the DTO and 
EntityManager details explained above). 


I've had this discussion with Adam Bien in the past (whom I enjoy sharing 
conference slots with regularly). I recommend watching his talks because they 
are very enthusiastic and show a lot of the power of JavaEE. Especially if you 
have some junior devs and like them to get the basic ideas and power of JavaEE 
or if you like to get a good overview about new features of the latest JavaEE 
version.

But he also tends to over-simply his samples and leaves out lots of very 
important parts - like the Oracle/Sun docs do as well. 

Adams argument is pretty straight forward. Of course he knows all those nasty 
details, but if he would go into those details then he could only explain one 
or two single features of JavaEE during each sessions. And he would utterly 
confuse listeners by explaining details which they do not get anyway. I can 
completely understand his position, but I believe for creating *real* 
applications, you need to know about all those gory details :/
That's the reason why I regularly do 'Pitfalls in JavaEE' kind of lectures on 
javaeesummit and other events.


Oki, back to @Version.
This is what provides you with locking.
There are 2 ways of locking in the database

a.) pessimistic locking, also known as database row locking (if you are happy 
it only locks the row in a table. Could also lock the whole table depending on 
indexes, etc). This requires an open database connection, so nothing you 
usually like to do in a web application. See JPA LockMode.PESSIMISTIC_READ, etc;

b.) optimistic locking. This is what you usually use in web apps. There is no 
database locking involved. Imagine you have a CUSTOMER table with the following 
columns:
* id* name
* birthdate

Now imagine a secretary A opens customer 'Jack' with id=1 and changes the name 
to 'Jill'. He lets the edit page open for around 4 hourse because he went to 
lunch. In the meantime another secretary B opened the same row, changed the 
birthdate and stores it. Finally secretary A saves his edit page. What happens 
is 

UPDATE CUSTOMER set name='Jill', birthdate='old' where id =1;
which means that all the changes done by secretary B get overwritten and are 
ultimately lost!

With optimistic locking you would not have this problem. You just need an 
additional 'version' integer column

* id
* version
* name
* birthdate

and the update performed by JPA will look like this:

UPDATE CUSTOMER set name='Jill', birthdate='old', version=:oldversion+1 where 
id = 1 and version = :oldversion;

where the oldversion is the version number (e.g. 1) at the time you did load it 
from the database.
If anyone has updated the row and incremented the version in the meantime then 
your update will fail and you could detect this as OptimisticLockException and 
force the 2nd user to first reload the values from the DB again and then apply 
his changes on top of the new data. That way you do not loose information.

I've now uploaded one of my half day lectures to my people account [3]. Hope 
you can find some valuable info in there



[1] http://deltaspike.apache.org/jpa.html

[2] http://people.apache.org/~struberg/jax2013/cdi-deep-dive_1.1_jax2013.pdf
[3] 
http://people.apache.org/~struberg/eesummit2013/Java%20EE%20Summit%20-%20pitfalls%20in%20EE.pdf



>________________________________
> From: "Howard W. Smith, Jr." <[email protected]>
>To: [email protected]; Mark Struberg <[email protected]> 
>Sent: Saturday, 19 October 2013, 14:06
>Subject: Re: Entity cant be refreshed with new list values
> 
>
>
>wow, interesting response, (thanks) Mark! responses inline..
>
>
>
>
>On Sat, Oct 19, 2013 at 3:16 AM, Mark Struberg <[email protected]> wrote:
>
>Much easier solution:
>>mark the fields you don't like to persist as
>>@javax.persistence.Transient
>>
>
>
>interesting, did not know this.
> 
>
>>In standard EJBs you will get the entitymanager-per-transaction pattern. 
>>Which means that any lazy loading field or relation you did not touch in your 
>>EJB will remain null forever.
>>
>
>
>i learned this after some time and work'ed around this by populating 
>lists/collections in 'other layer of app' after the EJB retrieved the @Entity, 
>where populating = use multiple other/corresponding EJBs to populate each 
>related List/Collection of @Entity. Bad design/performance, I'm sure.
>
>
>'did not touch'? i think you are referring to checking size() or isEmpty() on 
>Lists/collections that belong/related to @Entity... before @Entity is returned 
>from @EJB method. I think I read somewhere how size() and isEmpty() will 
>retrieve the data, but now I know, you must do this inside @EJB. right?
> 
>If you are aware of this restriction, then all is fine and you can use EJBs. 
>Nowadays a DTO is nothing more than making sure that you touch all the fields 
>an info you need in the other layer of your app,
>>
>
>
>It is interesting that you refer to it as a restriction. do you 
>prefer/recommend this approach, or another approach? I will have to see if I 
>can improve my app a bit by keeping this in mind (as I have bandwidth to do 
>so). thanks.
>
>
>
>>Btw, you should add a
>>
>>@Version
>>private Integer optlock;
>>
>>to all your entities. Otherwise you will not have any locking in the 
>>database. And of course if you use DTOs then you will also need to set this 
>>info into your DTO and do a manual comparison in your EJBs to make sure the 
>>entitiy did not get changed in the meantime.
>>
>
>
>are you recommending this for only OpenJPA users? I'm using EclipseLink and 
>(Apache) Derby. I think I read about this before somewhere; is the 'optlock' 
>part of Java EE implementation or just for OpenJPA users?
>
>
>
>
>
>

Reply via email to