用iBatis映射父子关系

发布于 2024-08-25 17:25:31 字数 1414 浏览 0 评论 0原文

我有经典的设置

public class Parent {
    Integer id;
    ...
    // No generics
    Collection someCollectionAttribute;
    ...
    public void setChildren(Collection c) {
        ...
    }
}

public class Child {
    Integer id;
    ...
}

,我正在尝试使用 iBatis (版本 2.30...不要问)将其映射到常用的表设置上。

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

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

我的映射文件看起来像这样

<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>

首先执行通常的 sqlMap.queryForObject("loadParent", new Integer(42)) 会在 setChildren setter 中导致 NullPointerException ,显然被调用带有空参数(我的错)。修复 setter 一切工作正常,但日志显示在运行单个 SQL 语句之前仅调用 setChildren 一次,仍然带有 null 参数,所以我想知道这里发生了什么。有人有任何线索吗?

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).

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

待"谢繁草 2024-09-01 17:25:31

我认为问题在于结果集中的列名(指定的别名)与 iBatis 结果映射中的映射不匹配。你的例子看起来不完整,所以我不能准确地告诉你。

无论如何,以下是与您的设置相匹配的完整工作示例(使用 iBatis 2.3.0.677 进行测试)。如果你将它与你拥有的进行比较,也许你就会找出问题所在。

数据库表:

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');

Bean:

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 映射:

<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>

如果您随后运行 sqlMap.queryForObject("loadParent", new Integer(1))sqlMap.queryForObject("loadParent", new Integer(2) ) 您应该分别获得一个带有两个子对象的父对象和一个带有四个子对象的父对象。

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.

缱绻入梦 2024-09-01 17:25:31

我相信关键是在 resultMap 中,应该使用 and 代替 .

<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>

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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文