开发者

Mapping parent-child relationships with iBatis

I have the classic setup

public class Parent {
    Integer id;
    ...
    // No generics
    Collection someCollectionAttribute;
    ...
    public void setChil开发者_StackOverflowdren(Collection c) {
        ...
    }
}

public class Child {
    Integer id;
    ...
}

and I'm trying to map this on the usual table setup using iBatis (version 2.30... don't ask).

create table parents (
    ID integer primary key
    ...
)

create table children (
    ID integer primary key
    PARENT_ID integer references parents(id)
    ...
)

My mapping file looks like this

<resultMap id="ParentResult" groupBy="id">
    <result property="id" column="ID" />
    ...
    <result property="children" resultMap="ChildResult" />
</resultMap>

<resultMap id="ChildResult">
    <result property="id" column="ID" />
    <result property="parentId" column="PARENT_ID" />
    ...
</result>

<sql id="loadParent" resultMap="ParentResult">
    select P.ID as p1, ..., C.ID as c1, C.PARENT_ID as c2 ...
    from   parents P
    join   children C on (P.ID = C.PARENT_ID)
    where  P.ID = #id#
    order by P.ID
</sql>

Doing the usual sqlMap.queryForObject("loadParent", new Integer(42)) at first caused a NullPointerException inside the setChildren setter which apparently is called with a null argument (my bad). Fixing the setter everything works fine, but the logs show that setChildren is called only once before even running a single SQL statement, still with a null argument, so I'm wondering what's going on here. Anyone has any clues?


I assume the problem is in the fact that your column names (your specified aliases) in the result set do not match the mappings from the result maps of iBatis. Your example looks incomplete so I can't tell exactly.

Anyhow, the following is a complete working example matching your setup (tested with iBatis 2.3.0.677). If you compare it with what you have maybe you will figure out where the problem is.

Database tables:

create table parents (
    ID integer primary key,
    BLA VARCHAR(100)
);

insert into parents(id, bla) values
(1, 'text1'),
(2, 'text2');

create table children (
    ID integer primary key,
    PARENT_ID integer references parents(id),
    BLA_CHILD VARCHAR(100)
);

insert into children(id, parent_id, bla_child) values
(10, 1, 'child for 1 1'),
(11, 1, 'child for 1 2'),

(12, 2, 'child for 2 1'),
(13, 2, 'child for 2 2'),
(14, 2, 'child for 2 3'),
(15, 2, 'child for 2 4');

Beans:

package model.pack;
import java.util.Collection;
public class Parent {
    private Integer id;
    private String bla;
    private Collection children;

    public Collection getChildren() {
        return children;
    }
    public void setChildren(Collection children) {
        this.children = children;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getBla() {
        return bla;
    }
    public void setBla(String bla) {
        this.bla = bla;
    }
}

package model.pack;
public class Child {
    private Integer id;
    private Integer parentId;
    private String bla;

    public Integer getParentId() {
        return parentId;
    }
    public void setParentId(Integer parentId) {
        this.parentId = parentId;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getBla() {
        return bla;
    }
    public void setBla(String bla) {
        this.bla = bla;
    }
}

Sql mapping:

<sqlMap>
    <resultMap id="childResult" class="model.pack.Child">
        <result property="id" column="childId" />
        <result property="parentId" column="childParentId" />
        <result property="bla" column="childBla" />
    </resultMap>

    <resultMap id="parentResult" class="model.pack.Parent" groupBy="id">
        <result property="id" column="parentId" />
        <result property="bla" column="parentBla" />
        <result property="children" resultMap="childResult" />
    </resultMap>

    <select id="loadParent" parameterClass="int" resultMap="parentResult">
        select p.id as parentId, p.bla as parentBla, c.id as childId, 
        c.bla_child as childBla, c.parent_id as childParentId
        from parents p left outer join children c
        on c.parent_id = p.id
        where p.id = #id#
        order by p.id
    </select>
</sqlMap>

If you then run sqlMap.queryForObject("loadParent", new Integer(1)) or sqlMap.queryForObject("loadParent", new Integer(2)) you should obtain a parent object with two children and a parent with four children respectively.


I believe the key is that in the resultMap, and should be used instead of <result>.

<resultMap id="ParentResult" groupBy="id">
    <result property="id" column="ID" />
    ...
    <collection property="children" javaType="ArrayList" ofType="Child" resultMap="ChildResult" />
</resultMap>

<resultMap id="ChildResult">
    <result property="id" column="ID" />
    <association property="parentId" foreignColumn="PARENT_ID" resultMap="ParentResult" />
    ...
</result>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜