After corresponding on the google-appengine-java Google Group, (actually after reading something in another thread), I realized what's causing the problem. For some reason, committing the transaction puts the entity into detached state--but closing the EM makes it transient, so in the next request it's persisting a transient object, which means that it's creating a new record--but it chokes on the fact that the PK is set to a Key with the id already set. So really it boils down to a JPA question--how do I get it to stay in detached state? Or, if I switch to JDO (which has explicit detaching control), how much work is it to not have ScalaJPA (or to write a ScalaJDO)? -----Original Message----- From: Derek Chen-Becker <dchenbec...@gmail.com> Sent: Tuesday, May 19, 2009 5:43 PM To: liftweb@googlegroups.com Subject: [Lift] Re: Trouble with lift, GAE, JPA, adding child records
I wonder if that's something specific to GAE. Typically what I do using the Hibernate EM is something like: val current = myAuthor // this entity has either been passed in or retrieved bind ("author", xhtml, "obj" -> hidden(() => authorVar(current)), ...) Then the actual instance is passed across the session instead of being retrieved each time. Obviously, if the entity is very large it's more efficient to do it by some other mechanism. Instead of doing a find I would do a load based on the id, since that will return a proxy instance that should track modifications. Derek On Tue, May 19, 2009 at 3:07 PM, ngug <naftoli...@gmail.com> wrote: I actually started my code by editing the AuthorOps snippet from ymnk's GAE version of it. He does reload the nature before editing it: // Hold a val here so that the "id" closure holds it when we re-enter this method bind("author", xhtml, "id" -> SHtml.hidden(() => findAuthor(author) match { case Some(a) => authorVar(a) case None =>}), "name" -> SHtml.text(author.name, author.name=_), "submit" -> SHtml.submit(?("Save"), doAdd)) findAuthor looks up the the author based on the id in the authorVar RequestVar, and then sets that back into the authorVar. I wondered why he did that, and then thought I understood... Thanks! On May 19, 5:01 pm, Derek Chen-Becker <dchenbec...@gmail.com> wrote: > On the first part, I could add a withTx method to LocalEM that would handle > wrapping the tx for you, if that's OK. Something like: > > def withTx[T] (f : => T) > > Then you could do > > MyEM.withTx { > prog > > } > > And it would handle the rollback. How does that sound? > > As for the second, if you're getting an exception on the merge I'd really > like to see the Exception (and code, if possible). Off the top of my head > the only time that should happen is if you have a constraint violation or > something similar that would throw and exception even if you were operating > on a non-detached entity. Take a look at the JPA Demo Library app. It does > detached object merge all of the time for editing authors and books. > > Derek > > On Tue, May 19, 2009 at 2:42 PM, ngug <naftoli...@gmail.com> wrote: > > > On May 19, 4:31 pm, Derek Chen-Becker <dchenbec...@gmail.com> wrote: > > > It should already. The closeEM method on both LocalEM and JndiEM checks > > to > > > see if the transaction has been marked rollback only and should handle > > > committing/rollback there. If it doesn't then it's a bug. > > But we're talking about userTx==true. I mean this: > > private def transaction(prog: =>Unit) { > > val tx = EntityManager.getTransaction > > try { > > tx.begin > > prog > > tx.commit > > } finally { > > if(tx.isActive) > > tx.rollback > > } > > } > > ... > > def get = transaction { > > val l = NatureLocationType.lookup(loc.id) > > l.name = stringValues("name") > > l.allowStreet = booleanValues("allowStreet") > > l.allowHospital = booleanValues("allowHospital") > > l.allowDoctor = booleanValues("allowDoctor") > > l.allowEquipment = booleanValues("allowEquipment") > > } > > (continued below) > > > > Also, for your first question: > > > > (I take that to mean that setting entity properties does not require a > > > > > transaction? I thought that in JPA entities are generally monitored > > > > for modifications? Is that a mistake?) > > > > In the context of a form processing function, the JPA entity is in a > > > "detached" state at the point that its members are being updated because > > the > > > session that it was loaded in (when the form rendered) is now closed. The > > > transaction is only required when you perform the "merge" of the detached > > > object into a new session to save the entity data. Whether or not the > > entity > > > is actually monitored is an implementation detail, since the spec only > > says > > > that when the entity is merged it should save data back to the database, > > but > > > it doesn't specify how that is done. Any exceptions related to JPA should > > > only occur during the flush, or possibly the merge if the JPA provider > > does > > > an eager flush to the database. This is why I added the mergeAndFlush, > > > persistAndFlush, and removeAndFlush methods, so that you would have a > > > definite place to wrap in a try/catch. If you're doing multiple ops then > > > you'll need to merge your entire block of merge,persist,remove and flush > > > methods in a try/catch. Does that make sense? I know that sometimes the > > > lifecycle of these things can take a few tries to wrap your head around, > > so > > > if this isn't clear let me know and I'll try to rephrase. > > > I understand you, and that's what I thought too, but I got an > > exception when I tried to merge a detached entity! If I could get an > > entity in one request, close the EM, and in the next request just > > modify it and merge it it would be great, but so far I haven't managed > > to. If you can't think of any explanation offhand I'll try to > > reproduce it in an isolated snippet. > > Thanks! > > > > Derek > > > > On Tue, May 19, 2009 at 2:07 PM, ngug <naftoli...@gmail.com> wrote: > > > > > P.S. I wrote a method to handle the boilerplate of opening/closing/ > > > > checking whether to rollback transactions. Shouldn't ScalaJPA have > > > > such a method? Or does it? > > > > Thanks. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Lift" group. To post to this group, send email to liftweb@googlegroups.com To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/liftweb?hl=en -~----------~----~----~----~------~----~------~--~---