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
-~----------~----~----~----~------~----~------~--~---

Reply via email to