一对多关系映射

一对多关系映射

上一节我们讲的是一对一的关系,这集我们来看一对多的关系。现在我们假设一个账号发表了多篇文章,所以添加一个文章表和一个文章实体类。

创建文章表和实体类

建表 SQL(简化示例):

DROP TABLE IF EXISTS `article`;
CREATE TABLE `article` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Title` varchar(100) NOT NULL,
  `AID` int(11) NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;Code language: JavaScript (javascript)

Article 实体类:

package cn.foxdevelop.models;

public class Article {
    private int ID;
    private String Title;
    private int AID;

    public int getID() {
        return ID;
    }
    public void setID(int iD) {
        ID = iD;
    }
    public String getTitle() {
        return Title;
    }
    public void setTitle(String title) {
        Title = title;
    }
    public int getAID() {
        return AID;
    }
    public void setAID(int aID) {
        AID = aID;
    }
}Code language: PHP (php)

修改 Account 类

在 Account 类中增加一个 Article 列表对象:

private List<Article> articles;

public List<Article> getArticles() {
    return articles;
public void setArticles(List<Article> articles) {
    this.articles = articles;
}Code language: PHP (php)

方式一:连表查询 + resultMap 映射

先往 Article 表中插入两条数据,都属于 Account 表中 ID 为 36 的用户。

SQL 语句:

SELECT * FROM account a, accountextend ae, article art 
WHERE a.ExtendID = ae.ID AND a.ID = art.AID AND a.ID = 36

映射文件配置:

<select id="getAccountAndArticles" parameterType="int" resultMap="AccountAndArticlesResultMap3">
    SELECT a.*, ae.ID AS EID, ae.EnglishName, art.ID AS artID, art.Title 
    FROM account a, accountextend ae, article art 
    WHERE a.ExtendID = ae.ID AND a.ID = art.AID AND a.ID = #{id}
</select>

<resultMap type="cn.foxdevelop.models.Account" id="AccountAndArticlesResultMap3">
    <id property="ID" column="ID"/>
    <result property="Name" column="Name"/>
    <result property="Age" column="Age"/>
    <association property="accountExtend" javaType="cn.foxdevelop.models.AccountExtend">
        <id property="ID" column="EID"/>
        <result property="EnglishName" column="EnglishName"/>
    </association>
    <collection property="articles" ofType="cn.foxdevelop.models.Article">
        <id property="ID" column="artID"/>
        <result property="Title" column="Title"/>
    </collection>
</resultMap>Code language: HTML, XML (xml)

执行代码:

Account account = session.selectOne("cn.foxdevelop.mapper.getAccountAndArticles", 36);
System.out.println(account.getName() + " - " + account.getAccountExtend().getEnglishName());
for (Article a : account.getArticles()) {
    System.out.println(a.getTitle());
}Code language: JavaScript (javascript)

输出结果:

张三 - zhangsan
不见不散
鸿雁

方式二:嵌套查询(分步查询)

映射文件配置:

<select id="getAccountAndArticles2" parameterType="int" resultMap="AccountAndArticlesResultMap4">
    select * from Account where id=#{id}
</select>

<resultMap type="cn.foxdevelop.models.Account" id="AccountAndArticlesResultMap4">
    <association property="accountExtend" column="ExtendID" select="getAccountExtend"/>
    <collection property="articles" ofType="cn.foxdevelop.models.Article" column="ID" select="getArticle"/>
</resultMap>

<select id="getAccountExtend" parameterType="int" resultType="cn.foxdevelop.models.AccountExtend">
    SELECT * FROM AccountExtend WHERE id=#{id}
</select>

<select id="getArticle" parameterType="int" resultType="cn.foxdevelop.models.Article">
    SELECT * FROM Article WHERE AID=#{id}
</select>Code language: HTML, XML (xml)

注意:最后查询文章时是通过 AID 列与 Account 表的 ID 关联的。

两种方式对比

第一种连表查询只查一次数据库,在多数情况下性能会比第二种嵌套查询(查两次)更好。但第二种方式代码结构更清晰,适合复杂场景按需选择。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注