A question from the JPADemo...
How does one use this:
def find[A](clazz: Class[A], id: Any) =
em.find[A](clazz, id).asInstanceOf[A]
If I have a User model and I want to use find on the EntityManager, what
goes where the *** is below:
val user = Model.find[User]( ***, userId)
Thanks,
Chas.
Derek Chen-Becker wrote:
> OK, let me try to tackle a few of these things at once. First of all,
> the hidden element is really just creating a function that is going to
> be run when the form is submitted. If you look at the HTML that's
> generated you'll see it like this:
>
> <input name="F977465725002233_OGX" type="hidden" value="true" />
>
> Basically what happens is that Lift processes form fields as functions.
> It looks up the function "F977...OGX" (in this case) and executes it. I
> believe (but am not 100% positive) that forms are executed in the
> sequence that they're submitted, which is usually the order in which
> they're defined. Anyways, back to the code at hand:
>
> "id" -> SHtml.hidden({category.id <http://category.id/> = currentId})
>
> It's going to call the category method (which if you're following the
> template is tied to a RequestVar). Since there isn't one already defined
> in the request, the default value of the RequestVar is constructed (new
> Category()) and returned. That's a big part of the problem with the
> current template (and something I'm fixing right now in my wip branch):
> we're not really editing the same object, we're making a brand new
> object and copying values. The issue is that, as you've found, any
> fields that you're not explicitly copying are reset to defaults. What we
> probably want to do instead is this:
>
> val ctgy = currentCategory // instead of currentId
> ...
> "id" -> SHtml.hidden(categoryVar(ctgy))
>
> or even
>
> "id" -> SHtml.hidden(categoryVar(Model.merge(ctgy))) // This
> automatically re-attaches the category to the entity manager
>
> and then all you'd be required to do in your submit is a Model.flush().
> Technically, the flush is implicit once the transaction closes at the
> end of the session, but if you have any constraints that you would want
> to handle violations on (i.e. a duplicate name, deleting something
> that's referenced as an FK), you need to do the flush at that point so
> that the exceptions get thrown. Otherwise, the exception is thrown as
> Lift is unwinding and your user gets a pretty stack trace.
>
> As for how Hibernate handles object lifecycle, I highly recommend
> reading this section of the hibernate EM docs:
>
> http://www.hibernate.org/hib_docs/entitymanager/reference/en/html/objectstate.html
>
> In particular, look at sections 3.1 and 3.6. Most of what we're doing
> here is working with detached objects. The merge method is what
> reattaches an object.
>
> I realize I'm still waving my hands a bit here and sweeping some
> plumbing details under the rug, but I hope this makes more sense now.
> Please feel free to ask questions. I'm actually working on the JPA
> chapter of the book right now, so you're helping me see where I need to
> clarify and explain things better :). I also need to refine the JPA
> demo, since the pattern that I'm currently using is non-optimal and even
> wrong in cases like yours.
>
> Derek
>
>
> On Mon, Oct 13, 2008 at 6:38 PM, Charles F. Munat <[EMAIL PROTECTED]
> <mailto:[EMAIL PROTECTED]>> wrote:
>
>
> Yeah, I'm really unclear on how this is being passed around and how the
> continuation works. For example, what does this line do:
>
> "id" -> SHtml.hidden({category.id <http://category.id> = currentId})
>
> I can see that it adds a hidden field in the form with the value true
> and the name of the field some sort of code. I can only presume that
> that code tells the snippet, upon submission of the form, that it should
> set the category.id <http://category.id> to currentId, thus handing
> the object back to the
> snippet. But how does this really work? What creates the code and what
> interprets it and recreates the object? I have been unable to figure
> this out.
>
> Also, I'm not entirely clear on hibernate. My understanding is that
> there is only one copy of any object, so if I pass the id of an object
> that already exists to my category, then I am manipulating the real
> object. Is that true? So when I "merge," I'm merging changes to that
> object into the persisted one?
>
> A problem I'm having because I don't really understand how this works is
> that I have a "createdAt" field in my objects which is a timestamp
> that's set to now() when the object is created. But everytime I update
> the object, it resets that field to a new "now()". And that is true for
> other fields as well. I can only guess that the object I'm merging isn't
> the same as the object in the database, and the null fields in my "new"
> object cause the fields in the database to be changed to the default
> values. That's not what I want, but I can't figure out how to get around
> it, and I'm not sure how to load the object in the database before
> manipulating it. Everything seems to work by magic, and I'm a lousy
> magician.
>
> Does any of this make any sense? I've got all this working at the
> moment, but thanks to magic. I really am not sure *why* or *how* it is
> working. I'd love to have a better understanding of this, but it's an
> uphill battle especially given how much I need to get done in how little
> time (so not much time for research).
>
> Thanks, BTW, for all your help, Derek. You have basically saved my ass
> on this and many other projects and if I can do the same for you anytime
> please let me know.
>
> Chas.
>
> Derek Chen-Becker wrote:
> > When you go to edit, are you passing the Category to be edited
> into the
> > categoryVar RequestVar? For instance, in your listing code say
> you had
> > something like:
> >
> > def list (xhtml : NodeSeq) : NodeSeq = {
> > Model.createQuery[Category]("from
> Category").findAll.flatMap({category =>
> > <tr>
> > <td>{category.name <http://category.name>
> <http://category.name>}</td>
> > <td>{Shtml.link("/admin/categories/add", () =>
> > categoryVar(category), Text("Edit"))}</td>
> > </tr>
> > }
> >
> > Otherwise I don't see in your code where the categoryVar is being
> > populated other than the default (new Category()).
> >
> > Derek
> >
> >
> > On Sat, Oct 11, 2008 at 1:35 PM, Charles F. Munat <[EMAIL PROTECTED]
> <mailto:[EMAIL PROTECTED]>
> > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>> wrote:
> >
> >
> > OK, I tried that. Still no luck. I also went back to just
> using bind:
> >
> > <lift:CategoryOps.editor form="POST">
> > <category:id />
> > <category:name />
> > <category:submit />
> > </lift:CategoryOps.editor>
> >
> > And
> >
> > object categoryVar extends RequestVar(new Category())
> > def category = categoryVar.is
> >
> > def editor(xhtml : NodeSeq) : NodeSeq = {
> > def addOrUpdate() = {
> > if (category.name.length == 0) {
> > error("emptyCategory", "The category's name cannot be
> blank")
> > } else {
> > Model.merge(category)
> > redirectTo("/admin/categories/")
> > }
> > }
> >
> > val currentId = category.id <http://category.id>
> <http://category.id>
> >
> >
> > bind("category", xhtml,
> > "id" -> SHtml.hidden({category.id <http://category.id>
> <http://category.id> =
> > currentId}),
> > "name" -> SHtml.text(category.name
> <http://category.name> <http://category.name>,
> > category.name <http://category.name> <http://category.name> = _),
> > "submit" -> SHtml.submit("Save", addOrUpdate))
> > }
> >
> > Everything works just fine on add, but on update the form is not
> > populated because category is a new Category, not the one
> from the
> > database (I checked).
> >
> > Any ideas?
> >
> > Chas.
> >
> >
> > Derek Chen-Becker wrote:
> > > OK, one thing I see in your code is that your editor
> snippet is
> > emitting
> > > the "form" tag. You really shouldn't do it that way. The
> snippet tag
> > > should look like
> > >
> > > <lift:CategoryOps.editor form="POST" />
> > >
> > > Otherwise I don't think the action won't get correctly
> populated. I
> > > don't know if that would cause the form elements to not be
> bound as
> > > well, but let's start with that.
> > >
> > > Derek
> > >
> > >
> > > On Fri, Oct 10, 2008 at 5:36 PM, Charles F. Munat
> <[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>
> > > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>>> wrote:
> > >
> > >
> > > For example, here is what I get when I go to the
> categories
> > list page
> > > (which lists them just beautifully):
> > >
> > > Hibernate: select category0_.id as id2_,
> category0_.CREATED_AT as
> > > CREATED2_2_, category0_.name as name2_,
> > category0_.UPDATED_AT as
> > > UPDATED4_2_ from CATEGORIES category0_ order by
> category0_.name
> > > WARN - Snippet Failure:
> SnippetFailure(/admin/categories/ ->
> > > ParsePath(List(admin, categories,
> > > index),,true,true),Full(Menu.link),Stateful Snippet:
> > Dispatch Not
> > > Matched)
> > > WARN - Snippet Failure:
> SnippetFailure(/admin/categories/ ->
> > > ParsePath(List(admin, categories,
> > > index),,true,true),Full(Menu.link),Stateful Snippet:
> > Dispatch Not
> > > Matched)
> > > INFO - Service request (GET) /admin/categories/ took 28
> > Milliseconds
> > > INFO - Service request (GET) /ajax_request/liftAjax.js
> took 1
> > > Milliseconds
> > >
> > > So there are two warnings for each page view.
> > >
> > > Chas.
> > >
> > > David Pollak wrote:
> > > > You have to define a package for Category.scala
> > > >
> > > > On Fri, Oct 10, 2008 at 4:00 PM, Charles F. Munat
> > <[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>
> > > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>>
> > > > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>
> > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>>>> wrote:
> > > >
> > > >
> > > > Thanks, Derek. Actually, I don't use .html or even
> > "add" (all
> > > my html
> > > > files are called index.html -- I use
> directories to sort
> > > them). This
> > > > error came when I was experimenting to see if
> that made a
> > > difference.
> > > >
> > > > That said, I get the error all the time. I
> don't have val
> > > dispatch... in
> > > > my snippets. But that's because I copied the
> JPADemo over,
> > > and your
> > > > AuthorOps and BookOps don't have the val dispatch
> > either. But the
> > > > JPADemo doesn't get this error.
> > > >
> > > > Also, my edit functions don't work -- the forms are
> > not populated
> > > > properly. I thought I had it working a minute
> ago, and
> > now it
> > > isn't
> > > > again.
> > > >
> > > > I switched the snippets around a bit and
> dropped the bind
> > > (because I
> > > > wanted to color code alternate rows and wasn't sure
> > how to do it
> > > > otherwise). Here is an example:
> > > >
> > > > snippet/Category.scala:
> > > >
> > > > import scala.xml.{NodeSeq,Text}
> > > >
> > > > import net.liftweb.http.{RequestVar,S,SHtml}
> > > > import net.liftweb.util.Helpers
> > > > import S._
> > > > import Helpers._
> > > >
> > > > import Model._
> > > >
> > > > class CategoryOps {
> > > > val formatter = new
> java.text.SimpleDateFormat("dd
> > MMM yyyy")
> > > >
> > > > def getRowClass(r: Int) = {
> > > > if (r % 2 == 0) "even" else "odd"
> > > > }
> > > >
> > > > def list: NodeSeq = {
> > > > <tr valign="top" align="left">
> > > > <th class="text">Name</th>
> > > > <th class="integer">Links</th>
> > > > <th class="blank"> </th>
> > > > <th class="blank"> </th>
> > > > </tr> ::
> > > >
> > > >
> > >
> >
>
> Model.createNamedQuery[Category]("findAllCategories").getResultList().toList.zipWithIndex.flatMap(c
> > > > => <tr valign="top" class={getRowClass(c._2)}>
> > > > <td class="text">{c._1.name
> <http://1.name> <http://1.name>
> > <http://1.name>
> > > <http://1.name>}</td>
> > > > <td
> > class="integer">{SHtml.link("/links/search/", {() =>
> > > >
> > > WeblinkOps.resultVar(Model.createNamedQuery[Weblink](
> > > > "findWeblinksByCategory", "id" -> category.id
> <http://category.id>
> > <http://category.id>
> > > <http://category.id>
> > > > <http://category.id>).getResultList().toList)
> > > > },
> Text(category.weblinks.size().toString))}</td>
> > > > <td class="edit">{SHtml.link("editor", () =>
> > > > categoryVar(category), Text("Edit"))}</td>
> > > > <td class="delete"> </td>
> > > > </tr>)
> > > > }
> > > >
> > > > object categoryVar extends RequestVar(new
> Category())
> > > > def category = categoryVar.is
> > > >
> > > > def editor (xhtml : NodeSeq) : NodeSeq = {
> > > > def addOrUpdate () = {
> > > > if (category.name.length == 0) {
> > > > error("emptyCategory", "The category's name
> > cannot be
> > > blank")
> > > > } else {
> > > > Model.merge(category)
> > > > redirectTo("/admin/categories/")
> > > > }
> > > > }
> > > >
> > > > val currentId = category.id
> <http://category.id> <http://category.id>
> > <http://category.id>
> > > <http://category.id>
> > > >
> > > > <form method="POST" action="">
> > > > <table class="editor" border="0"
> cellpadding="3"
> > > cellspacing="0">
> > > > <tr valign="top" align="left">
> > > > <th>Name</th>
> > > > <td>{SHtml.text(category.name
> <http://category.name>
> > <http://category.name>
> > > <http://category.name> <http://category.name>,
> > > > category.name <http://category.name>
> <http://category.name>
> > <http://category.name> <http://category.name> =
> > > _)}</td>
> > > > </tr>
> > > > <tr valign="top" align="left">
> > > > <th>{SHtml.hidden({category.id
> <http://category.id>
> > <http://category.id> <http://category.id>
> > > <http://category.id> =
> > > > currentId})} </th>
> > > > <td>{SHtml.submit("Save",
> addOrUpdate)}</td>
> > > > </tr>
> > > > </table>
> > > > </form>
> > > > }
> > > > }
> > > >
> > > > webapp/admin/categories/editor/index.html:
> > > >
> > > > <lift:surround with="default" at="content">
> > > > <h2>Categories</h2>
> > > > <table class="list">
> > > > <lift:CategoryOps.list/>
> > > > </table>
> > > > </lift:surround>
> > > >
> > > > And in Boot.scala:
> > > >
> > > > Menu(Loc("categories", List("admin", "categories",
> > "index"),
> > > > "Categories", LocGroup("admin")),
> > > > Menu(Loc("categories_add", List("admin",
> "categories",
> > > "editor",
> > > > "index"), "Add a New Category", Hidden))
> > > > ),
> > > >
> > > > ANY suggestions for how to do any of this
> better greatly
> > > appreciated. Do
> > > > I need to add the val dispatch... part? If so,
> why is this
> > > different
> > > > from the JPADemo?
> > > >
> > > > Thanks!
> > > > Chas.
> > > >
> > > >
> > > > Derek Chen-Becker wrote:
> > > > > It means that the dispatch function on whatever
> > Stateful
> > > Snippet is
> > > > > being called isn't matching what you're
> asking it to
> > > provide. For
> > > > > instance, if your snippet tag looks like
> > > > >
> > > > > <lift:MySnippet.add>
> > > > >
> > > > > Then the dispatchPf in the MySnippet stateful
> > snippet has
> > > to have a
> > > > > dispatch function like:
> > > > >
> > > > > val dispatch: DispatchIt = {
> > > > > case "add" => <some function here> _
> > > > > }
> > > > >
> > > > > See
> > > > >
> > > >
> > >
> >
>
> http://scala-tools.org/mvnsites-snapshots/liftweb/lift-webkit/scaladocs/index.html
> > > > > for more details.
> > > > >
> > > > > I also know that David has recently /strongly/
> > recommended not
> > > > putting
> > > > > ".html" on the ends of things.
> > > > >
> > > > > Derek
> > > > >
> > > > > On Fri, Oct 10, 2008 at 3:15 PM, Charles F.
> Munat
> > > <[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>
> > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>>
> > > > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>
> > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>>>
> > > > > <mailto:[EMAIL PROTECTED]
> <mailto:[EMAIL PROTECTED]> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL
> PROTECTED]>>
> > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>>
> > > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>
> > <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
> <mailto:[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>>>>> wrote:
> > > > >
> > > > >
> > > > > What exactly does this mean? I get a lot
> of these.
> > > > >
> > > > > WARN - Snippet Failure:
> > > SnippetFailure(/admin/users/add.html ->
> > > > > ParsePath(List(admin, users,
> > add),html,true,false),
> > > > > Full(Menu.link),
> > > > > Stateful Snippet: Dispatch Not Matched)
> > > > >
> > > > > What is failing here and what are the
> probable
> > causes?
> > > > >
> > > > > Thanks.
> > > > >
> > > > > Chas.
> > > > >
> > > > >
> > > > >
> > > > >
> > > > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > > --
> > > > Lift, the simply functional web framework
> http://liftweb.net
> > > > Collaborative Task Management http://much4.us
> > > > Follow me: http://twitter.com/dpp
> > > > Git some: http://github.com/dpp
> > > >
> > > > >
> > >
> > >
> > >
> > >
> > > >
> >
> >
> >
> >
> > >
>
>
>
>
> >
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---