mybatis多个一对多关系重复实体

时间:2014-09-07 07:16:15

标签: mybatis

我有三个表:grandparentparentchild。模型非常简单:祖父母有很多父母,父母有很多孩子。并且,我想在一个grandparent对象中检索它们的聚合。

这是我对这些表的DDL:

CREATE TABLE grandparent (
    id BIGINT NOT NULL,
    name VARCHAR(32) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE parent (
    id BIGINT NOT NULL,
    name VARCHAR(32) NOT NULL,
    grandparent_id BIGINT NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE child (
    id BIGINT NOT NULL,
    name VARCHAR(32) NOT NULL,
    parent_id BIGINT NOT NULL,
    PRIMARY KEY (id)
);

而且,这是我的MyBatis映射器文件:

<mapper namespace="me.predatorray.mybatis.GrandparentMapper">
    <!-- grandparent -->
    <resultMap id="grandparentResultMap" type="me.predatorray.mybatis.Grandparent">
        <constructor>
            <idArg column="grandparent.id" javaType="long" jdbcType="BIGINT"/>
            <arg column="grandparent.name" javaType="java.lang.String" jdbcType="VARCHAR"/>
        </constructor>
        <collection property="parents" column="parent.id" notNullColumn="parent.id"
                    javaType="java.util.ArrayList" ofType="me.predatorray.mybatis.Parent">
            <constructor>
                <idArg column="parent.id" javaType="long" jdbcType="BIGINT"/>
                <arg column="parent.name" javaType="java.lang.String" jdbcType="VARCHAR"/>
            </constructor>
            <collection property="children" column="child.id" notNullColumn="child.id"
                        javaType="java.util.ArrayList" ofType="me.predatorray.mybatis.Child">
                <constructor>
                    <idArg column="child.id" javaType="long" jdbcType="BIGINT"/>
                    <arg column="child.name" javaType="java.lang.String" jdbcType="VARCHAR"/>
                </constructor>
            </collection>
        </collection>
    </resultMap>

    <select id="findGrandparentById" parameterType="long" resultMap="grandparentResultMap">
        SELECT * FROM grandparent
        LEFT JOIN parent ON grandparent.id = parent.grandparent_id
        LEFT JOIN child ON parent.id = child.parent_id
        WHERE grandparent.id = #{id, jdbcType=BIGINT};
    </select>
</mapper>

而且,这是我的实体类:

public class Grandparent {

    private Long id;
    private String name;
    private Collection<Parent> parents;

    public Grandparent(Long id, String name) {
        this.id = id;
        this.name = name;
        this.parents = new ArrayList<Parent>();
    }

    public void setParents(Collection<Parent> parents) {
        this.parents = parents;
    }

    ...getters
}

public class Parent {

    private Long id;
    private String name;
    private Collection<Child> children;

    public Parent(Long id, String name) {
        this.id = id;
        this.name = name;
        this.children = new ArrayList<Child>();
    }

    public void setChildren(Collection<Child> children) {
        this.children = children;
    }

    ...getters
}

public class Child {

    private Long id;
    private String name;

    public Child(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    ...getters
}

但是,我的映射器似乎有问题。返回的祖父对象不是我所期望的。祖父母中有重复的父母。例如,鉴于以下情况,

INSERT INTO grandparent (id, name) VALUES (3, 'Daisy');

    INSERT INTO parent (id, name, grandparent_id) VALUES (2, 'Elizabeth', 3);
        INSERT INTO child (id, name, parent_id) VALUES (1, 'Frieda', 2);

    INSERT INTO parent (id, name, grandparent_id) VALUES (3, 'Grace', 3);
        INSERT INTO child (id, name, parent_id) VALUES (2, 'Helen', 3);
        INSERT INTO child (id, name, parent_id) VALUES (3, 'Ivy', 3);

    INSERT INTO parent (id, name, grandparent_id) VALUES (4, 'Jack', 3);

findGrandparentById(3)会返回像

这样的祖父母
Daisy (Grandparent)
  Elizabeth (Parent)
    Frieda (Child)
  Grace (Parent)
    Helen (Child)
  Grace (Parent)
    (C)Ivy (Child)
  Jack (Parent)

&#34;恩&#34;谁有两个孩子在#34; Daisy&#34;中重复两次。那么,问题是什么?

修改

给所有列命名后(例如,grandparent.id AS gid,parent.id AS pid等),问题就解决了。我只是想知道这可能是mybatis的错误吗?

1 个答案:

答案 0 :(得分:0)

问题是你的查询。尝试在SQL客户端中运行它 - 它将为Ivy和Helen返回单独的行。 MyBatis忠实地反映了这一点。

我怀疑您想要的结果不太可能通过简单的查询来检索。您需要根据需要读取父表和子表,或者可能将完整的模型读入内存并从那里开始工作。

稍微OT:你真的需要三张桌子吗?该模型看起来像一个表,其中一个可选的parentId字段指向直接父级。