OK, I definitely see some problems here. Unfortunately I'm pretty tied up
for the rest of the evening, but if you don't mind waiting I promise to
write up a detailed response tomorrow. Let me just point out some things I
see:
1. You're calling merge (Model.merge(s)) on an object that you just
obtained via getReference. While it won't cause problems, it's redundant,
since the object returned from getReference already has its state managed.
2. I would probably set a val to the new Row first, instead of using a
wrapper to get at the last item in the s.rows collection. You also need to
persist the row object itself unless you've explicitly placed a Cascade on
s.rows. Otherwise, you're using an object that isn't really an entity which
might explain double entries.
3. Since this is AJAX you may not need to add the new Row object to the
s.rows collection at all at this point. Just setting the owner field on the
Row (not sure what it's actually called) but not persisting it should do
what you want in terms of only persisting on first update.
4. I think you might need an explicit flush in the AjaxText update
function
I also forgot to ask if you're using JTA or RESOURCE_LOCAL transactions.
Derek
On Tue, Dec 9, 2008 at 4:27 PM, Charles F. Munat <[EMAIL PROTECTED]> wrote:
>
> Derek Chen-Becker wrote:
> > Hmmm. It doesn't seem like this should be causing issues. Probably the
> > most common mistake made with merge is that merge returns an entirely
> > new object, so you discard the original.
>
> Ah! That's good to know. I think that after I used Model.merge(row) I
> expected row to be attached. But then maybe I should have used row =
> Model.merge(row)? So then row needs to be a var not a val?
>
> I am confused...
> > Also, if you want the change to
> > be immediately visible and to check constraints, etc, you need to
> > immediately flush. For instance:
> >
> > updateRow (row : Row) : Row = {
> > Model.merge(row)
> > Model.flush()
> > }
>
> Oh, yeah... I've been flushing so much my water bill doubled this month.
> Flush, flush, flush, but then I have twenty copies of each row... sigh.
>
> > It really should be that simple. I'd be happy to look at code if you'd
> > like to see where there might be issues. I've added some comments below:
>
> I can zip it up and send it to you if you're curious.
>
> > I'm assuming that at least this works flawlessly, right?
>
> I think so.
>
> > I'm not 100%, but you may need to actually set the owner field on the
> > row as well as adding it to the Survey.rows collection. If I remember
> > correctly, owner fields in objects belonging to collections aren't
> > automatically updated unless you explicitly set the Cascade property on
> > the collection.
>
> Yeah, this is very confusing. What I am currently doing is this:
>
> def getOneButton(xhtml: NodeSeq) : NodeSeq = {
> val survey: Survey = Model.createNamedQuery[Survey](...)
> .getSingleResult()
>
> SHtml.ajaxButton("Add a row",
> () => {
> AppendHtml("myTable", getRow(survey))
> }, ("class", "removeButton"
> )
> }
>
> def getRow(survey: Survey): NodeSeq = {
>
> val s = Model.getReference[Survey](classOf[Survey], survey.id)
> s.rows.add(new Row())
> Model.merge(s)
> Model.flush()
> val row = JPA.listToWrapper(s.rows).last
>
> <tr id={"row" + row.id.toString}>
> <td class="text">{SHtml.ajaxText(row.colOne,
> (txt: String) => {
> row.colOne = txt
> Model.merge(row)
> Noop
> },
> ("id", "colOne" + row.id.toString), ("size", "8"))}</td>
> ...
> </tr>
>
> }
>
> > In your add row method, did you persist the new Row before returning it?
> > If not, it never gets an ID and then when it gets merged it will create
> > a new instance. I'd have to look at the code to see for sure.
>
> See above.
>
> > Actually, I think the case of a multi-page form is a good candidate for
> > an extended session, simply because you would likely want the entire
> > form to be treated atomically.
>
> Yes, although the client wanted every change to the form to be persisted
> immediately (no submit buttons), so I end up making lots of trips to the
> database. But there will only be a few dozen people taking this survey,
> so performance is not an issue. I have other sites with similar forms
> where that is not the case.
>
> > I'm having trouble visualizing what exactly the dirty flag is
> representing.
>
> I want to be able to strip out empty rows afterwards (since blank rows
> are persisted before they are sent to the browser). Rather than check
> every field in the row (there are seven), I have a flag (not really a
> dirty flag) called isNull or something like that. On the first change to
> a field, I set it to false. Then later I can delete all isNull == true
> rows to clean things up.
>
> If I could just create -- but not persist -- rows and persist them after
> the first field is updated, then that would be better. But I was having
> a really difficult time of that.
>
> > I think I mostly understand and it sounds like something is probably
> > wrong. I don't think what you're describing is the intended behavior for
> > JPA.
>
> Thanks. I'll zip up the site and send it to you off list (I'm not going
> to clean it). If you have a chance to look at the snippet, maybe you can
> see quickly what I'm doing wrong. Hopefully, it will also give you some
> ideas for how something like this could be added to the JPA example.
> That would be super.
>
> Chas.
>
> >
>
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---