Let me look. To save some time, can you give me an order of operations that result in the error that you're seeing?
Thanks, Derek On Tue, May 26, 2009 at 5:47 PM, Naftoli Gugenheim <[email protected]>wrote: > I guess it's a DataNucleus thing. Here's my project. > > > ------------------------------ > From: Derek Chen-Becker <[email protected]> > Sent: Tuesday, May 26, 2009 3:09 PM > To: [email protected] > Subject: [Lift] Re: Trouble with lift, GAE, JPA, adding child records > > The merge method really should be able to handle this, so could you provide > some code that shows how you're handling the entity in the two different > requests? I'm not sure what you mean by transient, either. JPA entities are > either in an attached or detached state; AFAIK there is no third state. > > Derek > > On Mon, May 25, 2009 at 2:04 PM, Naftoli Gugenheim > <[email protected]>wrote: > >> 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)? >> >> >> ------------------------------ >> From: Derek Chen-Becker <[email protected]> >> Sent: Tuesday, May 19, 2009 5:43 PM >> To: [email protected] >> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> wrote: >>> > >>> > > On May 19, 4:31 pm, Derek Chen-Becker <[email protected]> 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 <[email protected]> >>> 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 [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/liftweb?hl=en -~----------~----~----~----~------~----~------~--~---
