简体   繁体   English

使用iBatis映射父子关系

[英]Mapping parent-child relationships with iBatis

I have the classic setup 我有经典的设置

public class Parent {
    Integer id;
    ...
    // No generics
    Collection someCollectionAttribute;
    ...
    public void setChildren(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). 我正在尝试使用iBatis(版本2.30 ...不用问)将其映射到常规表设置上。

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). 首先执行通常的sqlMap.queryForObject("loadParent", new Integer(42))setChildren设置器内部引起NullPointerException,显然是使用null参数调用的(我不好)。 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. 修复setter一切正常,但是日志显示setChildren在运行单个SQL语句之前仅被调用过一次,但仍带有null参数,因此我想知道这里发生了什么。 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. 我认为问题在于事实,您在结果集中的列名(您指定的别名)与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). 无论如何,以下是与您的设置相匹配的完整工作示例(已通过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: SQL映射:

<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. 如果然后运行sqlMap.queryForObject("loadParent", new Integer(1))sqlMap.queryForObject("loadParent", new Integer(2)) ,则应分别获得一个有两个孩子的父对象和一个有四个孩子的父对象。

I believe the key is that in the resultMap, and should be used instead of <result>. 我相信关键是在resultMap中,应该使用它而不是<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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM