[Lift] Re: Trouble with lift, GAE, JPA, adding child records

2009-05-27 Thread Derek Chen-Becker
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 naftoli...@gmail.comwrote:

 I guess it's a DataNucleus thing. Here's my project.


 --
 From: Derek Chen-Becker dchenbec...@gmail.com
 Sent: Tuesday, May 26, 2009 3:09 PM
 To: liftweb@googlegroups.com
 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 
 naftoli...@gmail.comwrote:

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

[Lift] Re: Trouble with lift, GAE, JPA, adding child records

2009-05-26 Thread Derek Chen-Becker
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 naftoli...@gmail.comwrote:

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

[Lift] Re: Trouble with lift, GAE, JPA, adding child records

2009-05-19 Thread ngug

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

2009-05-19 Thread Derek Chen-Becker
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...@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

2009-05-19 Thread ngug

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 

[Lift] Re: Trouble with lift, GAE, JPA, adding child records

2009-05-19 Thread ngug

בה 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

2009-05-19 Thread ngug

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

2009-05-19 Thread Derek Chen-Becker
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.

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.

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

2009-05-19 Thread ngug



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

2009-05-19 Thread Derek Chen-Becker
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

2009-05-19 Thread ngug

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

2009-05-15 Thread ngug

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

2009-05-15 Thread Derek Chen-Becker
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

2009-05-14 Thread ngug

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

2009-05-14 Thread ngug

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

2009-05-14 Thread ngug

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

2009-05-13 Thread ngug

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

2009-05-13 Thread Derek Chen-Becker
I took a quick look and nothing is jumping out at me as wrong. When you get
these errors do you at least get a stack trace? Having that would help
narrow down where it's happening.

Derek

On Tue, May 12, 2009 at 5:40 PM, ngug naftoli...@gmail.com wrote:


 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 = _),
  

[Lift] Re: Trouble with lift, GAE, JPA, adding child records

2009-05-13 Thread ngug

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: Trouble with lift, GAE, JPA, adding child records

2009-05-13 Thread Derek Chen-Becker
JPA requires that a transaction be in place before *any* persistence
operations occur. The ScalaJPA stuff is supposed to handle it for you, so
that's why I was wondering about stack traces. In particular, the
RequestVarEM trait should start a new transaction when the request begins
and close the transaction on exit.

Derek

On Wed, May 13, 2009 at 2:14 PM, ngug naftoli...@gmail.com wrote:


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