Ok, I think I've struggled with this long enough to warrant posting here,
although I'm still not sure if this is a bug or me not understanding
something.. I think the only way I can explain this is by example so if
you'll bare with me. Below are some C# classes I'm mapping:
public class Child
{
private Nullable<Int32> id = null;
public virtual Nullable<Int32> Id
{
get { return id; }
set { id = value; }
}
private String name;
public String Name
{
get { return name; }
set { name = value; }
}
}
public class Parent
{
public Parent()
{
marriageOne = new List<Child>();
marriageTwo = new List<Child>();
}
private Nullable<Int32> id = null;
public virtual Nullable<Int32> Id
{
get { return id; }
set { id = value; }
}
private IList<Child> marriageOne;
public IList<Child> MarriageOne
{
get { return marriageOne; }
}
private IList<Child> marriageTwo;
public IList<Child> MarriageTwo
{
get { return marriageTwo; }
}
}
Note that there are two lists of type Child in the Parent class. The mapping
is as follows:
<resultMaps>
<resultMap id="parent" class="Parent" groupBy="id">
<result property="id" column="Parent_ID"/>
<result property="marriageOne" resultMapping="Test.marriageOneList"/>
<result property="marriageTwo" resultMapping="Test.marriageTwoList"/>
</resultMap>
<resultMap id="marriageOneList" class="Child">
<result property="id" column="MarriageOne_ID"/>
<result property="name" column="MarriageOne_Name"/>
</resultMap>
<resultMap id="marriageTwoList" class="Child">
<result property="id" column="MarriageTwo_ID"/>
<result property="name" column="MarriageTwo_Name"/>
</resultMap>
</resultMaps>
Here beings the strangeness, if marriageOne has a single Child and
marriageTwo has two children (in the database), iBatis gives me two of the
same child in marriageOne. The inverse is true also, if marriageTwo has a
single Child and marriageOne has two, iBatis returns two identical children
in marriageTwo. This is easily solved, add a groupBy="id" on the two
resultMaps marriageOneList and marriageTwoList. The results from the
database looks like this:
Parent_ID MarriageOne_ID MarriageOne_Name MarriageTwo_ID
MarriageTwo_Name
20 30 Child One 40 Child Two
20 30 Child One 50 Child Three
This works great untill we add a GrandParent:
public class GrandParent
{
public GrandParent()
{
parents = new List<Parent>();
}
private Nullable<Int32> id = null;
public virtual Nullable<Int32> Id
{
get { return id; }
set { id = value; }
}
private IList<Parent> parents;
public IList<Parent> Parents
{
get { return parents; }
}
}
<resultMap id="grandParent" class="GrandParent" groupBy="id">
<result property="id" column="GrandParent_ID"/>
<result property="parents" resultMapping="Test.parent"/>
</resultMap>
Now, let's say we have two parents, Parent1 and Parent2, Parent1 has one
Child in marriageOne and two in marriageTwo, and Parent2 has that same
single Child in marriageOne and nothing in marriageTwo (this is a pretty
messed up family :)). With groupBy="id" on the marriageOneList and
marriageTwoList, iBatis again returns the expected result for Parent1
however now Parent2 will show no children in marriageOne. The results from
the database look like this:
GrandParent_ID Parent_ID MarriageOne_ID MarriageOne_Name
MarriageTwo_ID MarriageTwo_Name
10 20 30 Child One 40 Child Two
10 20 30 Child One 50 Child Three
10 60 30 Child One NULL NULL
I hope that made some sense, it seems to me that the groupBy statements are
being evaluated in the wrong order leading to Child One being aggregated
into a single object. I'd be eternally grateful for any guidance on this,
I've wasted half a day isolating the problem and trying to find a
workaround.
Many thanks.