[Lift] Re: Trouble with lift, GAE, JPA, adding child records
Sorry for the delay in responding. My question was not about transaction API, my question was a practical one: If form processing is split into a bunch of little anonymous functions, how can you put them in a try/finally? On May 15, 1:59 pm, Derek Chen-Becker dchenbec...@gmail.com wrote: EntityManager has a getTransaction method that you can use along with the constructor I mentioned previously to explicitly begin and end transactions in your code. derek On Fri, May 15, 2009 at 11:45 AM, ngug naftoli...@gmail.com wrote: One entity group per transaction is a GAE requirement. But my question about handling transactions was more specific - because form processing is specified piecemeal in separate closures, you can't use the normal try/finally. It seems a little too much effort to create a hidden field before and after every form/subform. Thanks. P.S. Sorry about the triple post. Opera Mobile (well, Google) didn't tell me the post was successful like it usually does, so I thought it didn't go through. (I thought the list is moderated and you would filter the extras just in case.) --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: Trouble with lift, GAE, JPA, adding child records
Thanks for the fast response! Okay, a couple of things: 1. Well, typically the form callbacks are just setting values. If they're more ... (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?) Look at my code for setting the location. def bindLocation(loc: NatureLocationType) = { var l = loc bind(location, chooseTemplate(each, location, xhtml), id - SHtml.hidden(()= l = NatureLocationType.lookup (loc.id)), name - SHtml.text(l.name, l.name = _), allowStreet - SHtml.checkbox(l.allowStreet, l.allowStreet = _), allowHospital - SHtml.checkbox(l.allowHospital, l.allowHospital = _), allowDoctor - SHtml.checkbox(l.allowDoctor, l.allowDoctor = _), allowEquipment - SHtml.checkbox(l.allowEquipment, l.allowEquipment = _), removeBtn - SHtml.submit(?(Remove), ()=removeLocation(l)) ) } Because the entity manager is closed after each request, the location has to be reloaded in order to be modified. So loading it has to be done in a transaction, but can I end the transaction before I set the properties? 2. In the mean time I made my own whole-form processor. Unfortunately it's a little verbose to use. Here's the code (currently only supports text boxed and check boxes, and string values and boolean values, but it's very easy to extend): import scala.xml.{Group, Elem, NodeSeq} import scala.collection.mutable.{Map = mMap} import net.liftweb.http.SHtml import net.liftweb.util.{Helpers, Full, Empty} import Helpers._ abstract class FormProcessor(prefix: String) { def text(attrs: (String, String)*)(init: String, action: String=Unit) = SHtml.text(init, action, attrs:_*) def text: (String,String=Unit)=NodeSeq = text()_ def checkbox(attrs: (String, String)*)(init: Boolean, action: Boolean=Unit) = SHtml.checkbox(init, action, attrs:_*) def checkbox: (Boolean, Boolean=Unit)=NodeSeq = checkbox()_ val stringValues: mMap[String, String] = mMap.empty[String, String] val strings = mMap.empty[String, (String,String=Unit)=NodeSeq] val booleanValues = mMap.empty[String, Boolean] val booleans = mMap.empty[String, (Boolean,Boolean=Unit)=NodeSeq] def bind(xhtml: NodeSeq) = { def transform(node: NodeSeq): NodeSeq = { put node match { case Elem(`prefix`, label, _, _, _*) if strings.keys contains label = strings(label)(stringValues(label), stringValues(label) = _) case Elem(`prefix`, label, _, _, _*) if booleans.keys contains label = booleans(label)(booleanValues(label), booleanValues(label) = _) case other = other } } Helpers.bind(prefix, Full(transform _), Empty, xhtml) ++ Seq(SHtml.hidden(()=get)) } def put: Unit def get: Unit } And here's some usage: def bindLocation(loc: NatureLocationType) = { var l = loc val form = new lrbcol.FormProcessor(location) { strings += (name - text) booleans ++= Map(allowStreet-checkbox, allowHospital-checkbox, allowDoctor-checkbox, allowEquipment-checkbox) def put { stringValues(name) = l.name booleanValues ++= Map(allowStreet - l.allowStreet, allowHospital - l.allowHospital, allowDoctor - l.allowDoctor, allowEquipment - l.allowEquipment) } 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) } } bind(location, form.bind(chooseTemplate(each, location, xhtml)), removeBtn - SHtml.submit(?(Remove), ()=removeLocation (NatureLocationType.lookup(loc.id))) ) } If you have a better way of implementing it, let me know. Feel free to include it in lift, unmodified or modified. 3. I'll put it in the next post because it's somewhat separate. On May 19, 3:20 pm, Derek Chen-Becker dchenbec...@gmail.com wrote: Well, typically the form callbacks are just setting values. If they're more complex than that then you would need a try/catch in each function. I don't think that the current form processing code has any facility for a per-form exception handler, although that might be a useful feature. Derek On Tue, May 19, 2009 at 1:09 PM, ngug naftoli...@gmail.com wrote: Sorry for the delay in responding. My question was not about transaction API, my question was a practical one: If form processing is split into a bunch of little anonymous functions, how can you put them in a try/finally? On May 15, 1:59 pm, Derek Chen-Becker dchenbec
[Lift] Re: Trouble with lift, GAE, JPA, adding child records
בה using the FormProcessor, all my exceptions seem to have disappeared. Now I have a problem, that although seems to be a separate problem is very much intertwined with everything else and I think it's really one issue. The page basically looks like this: Nature Name: [text field] Locations: Name Allow St. Addr Allow Hosp. Addr Allow Doc. Allow Eqpmt Loc [text field] [X] [X] [ ] [ ][[Remove button]] [[Insert Row button]] [[Save button]] And you can add/remove locations, e.g. for nature Hospital Visitation you would have one location, called Location or Hospital which is only allowed to be a hospital (when you enter the request you'll get drop-downs). A Food delivery might have a From and a To, which can be street addresses, hospital rooms, or even a doctor's office, but it wouldn't let you select an equipment location. Now, this app is being rewritten, after I started it in PHP. In the PHP version (I didn't know how to use multiple submit buttons then) adding and removing rows was done via a link, so it discarded any modifications you made to locations. (I'm trying to stay away from relying on Javascript). Now, with Lift, they are buttons, and so any modifications you make to locations are saved to the datastore immediately upon pressing them, because the page needs to reload with these locations. But neither of these behaviors is optimal. Really, it should keep track of your changes but only send them to the datastore when you explicitly press Save. But the page can get reloaded via Remove/Insert Row in between. Okay, so I made another RequestVar to hold pending new rows and rows pending removal, and it shows the page as if they were added and removed. But what happens if you modify the properties of a location and then insert a row? Modifying the location that that field was mapped to is pointless, because we don't want to merge it yet, but we're going to have to reload it from the datastore in a future request cycle, before we are able to merge it, because it doesn't seem to be able to merge an entity that was detached the last time the entity manager was closed. What am I supposed to do? Store everything in a fake (never persisted) nature/locations and then copy all the differences to the managed entity when processing the Save submit button? I hope you understand my question, let me know what needs clarification. Thanks a ton! --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: Trouble with lift, GAE, JPA, adding child records
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 -~--~~~~--~~--~--~---
[Lift] Re: Trouble with lift, GAE, JPA, adding child records
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 -~--~~~~--~~--~--~---
[Lift] Re: Trouble with lift, GAE, JPA, adding child records
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 -~--~~~~--~~--~--~---
[Lift] Re: Trouble with lift, GAE, JPA, adding child records
One entity group per transaction is a GAE requirement. But my question about handling transactions was more specific - because form processing is specified piecemeal in separate closures, you can't use the normal try/finally. It seems a little too much effort to create a hidden field before and after every form/subform. Thanks. P.S. Sorry about the triple post. Opera Mobile (well, Google) didn't tell me the post was successful like it usually does, so I thought it didn't go through. (I thought the list is moderated and you would filter the extras just in case.) --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: Trouble with lift, GAE, JPA, adding child records
In any case, how would I handle transactions manually? An SHtml.hidden before and after every form? It's confusing because SHtml lumps the get and set side by side when they happen in two different requests and the entity needs to be reloaded in between. In any case, GAE seems to require tighter control of transactions because two entity groups can't be modified (accessed?) in one transaction. --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: Trouble with lift, GAE, JPA, adding child records
In any case, how would I handle transactions manually? An SHtml.hidden before and after every form? It's confusing because SHtml lumps the get and set side by side when they happen in two different requests and the entity needs to be reloaded in between. In any case, GAE seems to require tighter control of transactions because two entity groups can't be modified (accessed?) in one transaction. --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: Trouble with lift, GAE, JPA, adding child records
In any case, how would I handle transactions manually? An SHtml.hidden before and after every form? It's confusing because SHtml lumps the get and set side by side when they happen in two different requests and the entity needs to be reloaded in between. In any case, GAE seems to require tighter control of transactions because two entity groups can't be modified (accessed?) in one transaction. --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: Constantly Ajax Request ?
Well since he may have meant that, to disable it you put in Boot: LiftRules.enableLiftGC = false On May 12, 8:01 pm, Timothy Perrett timo...@getintheloop.eu wrote: This im aware of - however it just seems more likely that if he asked for comet behavior by inserting the comet tag he would associate the two. However, the way the original query was worded indicated to me at least that he was not expecting the ajax calls... hence why i think he's probally talking about the GC page ajax rather than a comet call. Generally speaking people tend to exaggerate, hence his miss-use of constantly. I may be wrong, but i have a hunch... Cheers, tim Nope... the GC happens once every 75 seconds (by default). It's not constant. --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: Trouble with lift, GAE, JPA, adding child records
I guess I should include the views too to make it easier to reproduce the problem. Here is edit.html: lift:surround with=default at=content head titlelift:loc lift:Natures.newOrEdit if:editEdit/if:edit if:newNew/if:new /lift:Natures.newOrEditnbsp;Nature /lift:loc/title /head h3lift:loc lift:Natures.newOrEdit if:editUpdate/if:edit if:newCreate/if:new /lift:Natures.newOrEditnbsp;Request Nature/lift:loc/h3 lift:Natures.edit form=GET nature:id / fieldsetlegendlift:locName/lift:loc/legend nature:name / /fieldset fieldsetlegendlift:locLocations/lift:loc/legend table thead tr thLocation name/th th colspan=4Allowed locations/th th/th /tr /thead tr td/td tdStreet/td tdHospital/td tdDoctor/td tdEquipment/td td/td /tr nature:locations each:location tr tdlocation:id /location:name //td tdlocation:allowStreet //td tdlocation:allowHospital //td tdlocation:allowDoctorallowDoctorChk/location:allowDoctor/ td tdlocation:allowEquipmentallowEquipmentChk/ location:allowEquipment/td tdlocation:removeBtnRemoveBtn/location:removeBtn/td /tr /each:location /nature:locations tr td colspan=5/td tdnature:newLocationinsertLocationBtn/nature:newLocation/ td /tr /table /fieldset nature:submit / /lift:Natures.edit /lift:surround And here is list.html: lift:surround with=default at=content head titlelift:locNatures List/lift:loc/title /head h3Request Natures/h3 table thead tr thlift:locName/lift:loc/th thlift:locLocations/lift:loc/th th/th /tr /thead lift:Natures.list tr tdnature:name //td tdnature:locations //td tdnature:edit //td tdnature:remove //td /tr /lift:Natures.list a href=editlift:locNew/lift:loc/a /table /lift:surround --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: Trouble with lift, GAE, JPA, adding child records
Thanks for looking. The stack traces aren't very helpful because they concern the state which is caused by the previous sequence of events. Anyway, why is there a transaction taking place in the first place? --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: Lift works on Google App Engine (within the confines of what's possible)
Personally I couldn't find anything free, except for EatJ, which has a free trial. Apparently you have to restart the server every 6? hours in trial mode. Anyway, soon after I registered it didn't let me log in anymore, not sure why. On Apr 20, 8:56 am, Jeremy Mawson jeremy.mawson.w...@gmail.com wrote: Yes, for those who wish to tinker and share their tinkerings with the world, the zero cost entry point* is good. I'm also interested in any opinions of which free services are better than GAE for Lift apps. Cheers Jeremy * - yes, I know there is a billing model for increased bandwidth and other add-ons with GAE. 2009/4/20 samreid samrr...@gmail.com If GAE is not a good home for Lift applications, can you recommend some alternate hosts? Are there any free alternates? Thanks, Sam Reid On Apr 17, 3:57 pm, David Pollak feeder.of.the.be...@gmail.com wrote: Folks, I've just committed a version of Lift (including the Lift Example) that runs on the Google App Engine. You can see the running demo at: http://liftdemo.appspot.com/ What's missing: - Mapper and Mapper-related stuff. You can use JPA. - Comet. GAE's lack of thread or message queue support is a huge limitation. - Actor-based session-shutdown notification is disabled on GAE. - There's no session affinity guarantee, so there may be problems with migrating sessions (I'll be working with the Google folks on this issue) Okay... so you can build apps on GAE... I have to wonder... who would want to? GAE gives you a highly scalable platform to build CRUD apps. Without a back-end messaging infrastructure, long running processes, threads, inter-session messaging, etc. there's not much in the way of exciting apps to build. Here are a list of apps that could not be built with GAE: - Twitter (requires a message bus and back-ground processing) - Facebook (has many of Twitter's requirements) - GoogleTalk - A travel site (the 30 second request duration means that looking stuff up on a back end service is not possible) - A multi-player game So... on a $100/mo box from CalPop, I can run a service that will scale to 20M requests per day. If I'm doing 20M requests per day, I've got a business where I want more control over my infrastructure than GAE gives me. That might be Amazon EC2 where I can power-up and down boxes at will. There are also a number of different scalable storage solutions on Amazon. I just can't for the life of me figure out why anyone would want to put a Java/Scala app on GAE. Thanks, David -- Lift, the simply functional web frameworkhttp://liftweb.net Beginning Scalahttp://www.apress.com/book/view/1430219890 Follow me:http://twitter.com/dpp Git some:http://github.com/dpp -- Jeremy Mawson Senior Developer | Online Directories Sensis Pty Ltd 222 Lonsdale St Melbourne 3000 E: jeremy.maw...@sensis.com.au --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Trouble with lift, GAE, JPA, adding child records
I made the beginnings of a lift app for GAE. It's for a volunteer medical assistance organization, to manage requests that they get. Every request has a nature, e.g., transportation, hospital visitation, etc. Each nature has a OneToMany association with a NatureLocationType, which means that when you enter the request you have a different set of location fields depending on the nature. One screen lets you manage the natures. On the same screen that you edit the name of the nature you can add, remove, and edit location types for that nature. I'm new to lift, GAE, and JPA, although familiar with Scala. So far I'm only working with the dev server. I started with the lift JPA library demo's (snippet) code Anyway, after a while I got it pretty functional. (After discovering that after each request, when it processes the input from the previous request the same entity object is still in the JVM, but it has become detached and there's no way to reattach it other than re-looking it up via its id---why does the entity manager have a shorter lifespan than the entity?) However, every now and then I get an error that the object is dirty but no field are, and sometimes an error that a request completed without closing the (which?) transaction. Could someone look at the source code and help me? Thanks, it's really appreciated. Here's the source for the snippet class (models below; note that EntityManager is my name for what the library demo calls Model: object EntityManager extends LocalEMF(transactions-optional) with RequestVarEM): package liftgae1.snippet import javax.persistence.{EntityExistsException, PersistenceException} import scala.collection.jcl.Conversions.convertList import scala.xml.{NodeSeq, Text} import net.liftweb.http.{RequestVar, SHtml, S, StatefulSnippet} import S._ import net.liftweb.util.{Helpers, Log} import Helpers._ import lrbcol.model.{EntityManager, Nature, NatureLocationType} class Natures /*extends StatefulSnippet*/ { /* val dispatch: DispatchIt = { case list = list case newOrEdit = newOrEdit case edit = edit }*/ // Set up a requestVar to track the nature object for edits and adds private object natureVar extends RequestVar[Nature](new Nature) def nature: Nature = natureVar.is def nature_=(nature: Nature) = natureVar(nature) def hasNature = nature.id != null def reloadNature = if(hasNature) try {nature = Nature.lookup (nature.id).get} catch {case e = println(e)} def list(xhtml: NodeSeq): NodeSeq = { println(In list) Nature.all foreach println NatureLocationType.all foreach {l=println(l + for + l.nature)} Nature.all.flatMap { n = println(Binding with + n + , contained = + EntityManager.contains(n)) bind(nature, xhtml, name -Text(n.name), locations - Text(n.natureLocationTypes map {_.name} mkString ,), edit -SHtml.link(edit, () = nature = n, Text(?(Edit)) ), remove - SHtml.link(list, () = {nature = n; reloadNature; EntityManager.removeAndFlush(nature)}, Text(?(Remove)) ) ) } } def newOrEdit(xhtml: NodeSeq) = hasNature match { case false = chooseTemplate(if, new, xhtml) case _ = chooseTemplate(if, edit, xhtml) } def edit(xhtml: NodeSeq): NodeSeq = { def doSave() { println(In doSave with %s format(nature)) if (nature.name.isEmpty) { error(emptyNature, The nature's name cannot be blank) } else try { EntityManager.mergeAndFlush(nature) redirectTo(list) } catch { case ee: EntityExistsException = error(That nature already exists.) case pe: PersistenceException = error(Error adding nature); Log.error(Nature add failed, pe) } } def insertLocation() { val l = new NatureLocationType nature.natureLocationTypes += l l.nature = nature EntityManager.mergeAndFlush(if(hasNature) l else nature) } def removeLocation(l: NatureLocationType) { try { EntityManager.removeAndFlush(l) } catch { case e = e.printStackTrace } } println(In edit with nature %s. format(nature)) def bindLocation(loc: NatureLocationType) = { var l = loc bind(location, chooseTemplate(each, location, xhtml), id - SHtml.hidden(()= l = NatureLocationType.lookup (loc.id)), name - SHtml.text(l.name, l.name = _), allowStreet - SHtml.checkbox(l.allowStreet, l.allowStreet = _), allowHospital - SHtml.checkbox(l.allowHospital, l.allowHospital = _), allowDoctor - SHtml.checkbox(l.allowDoctor, l.allowDoctor = _), allowEquipment - SHtml.checkbox(l.allowEquipment, l.allowEquipment = _),