>'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? > > > > > >
