草庐IT

day08-MyBatis的关联映射02

liyuelian 2023-03-28 原文

MyBatis的关联映射02

3.一对多

3.1基本介绍

mybatis – MyBatis 3 | XML 映射器

多对一关系也是一个基本的映射关系,多对一,也可以理解为一对多。例如:

User--Pet:一个用户可以有多只宠物

Dep--Emp:一个部门有多个员工

双向的多对一关系:通过User可以查询到对应的所有Pet,反之,通过Pet也可以级联查询到对应的User信息。

多对多的关系就是在多对一的关系上拓展

3.2案例实现

映射方式:

方式1:通过配置映射文件实现多对一

方式2:通过注解的方式实现多对一

需求说明:实现级联查询,通过user的user_id可以查询到User信息和关联的所有pet信息,反之,通过pet的pet_id也可以查询到Pet信息和user的信息

先创建user表和pet表:

-- 创建user表
CREATE TABLE `user`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL DEFAULT ''
)CHARSET=utf8
DESC `user`;

-- 创建pet表
CREATE TABLE `pet`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`nickname` VARCHAR(32) NOT NULL DEFAULT '',
`user_id` INT,
FOREIGN KEY (user_id) REFERENCES `user`(id)
)CHARSET=utf8

3.2.1方式一:配置方式

(1)User和Pet实体类

package com.li.entity;

/**
 * @author 李
 * @version 1.0
 */
public class User {
    private Integer id;
    private String name;
    //因为一个User可以养多个宠物,mybatis使用集合体现这个关系
    private List<Pet> pets;
    
    //setter、getter方法省略
    //双向映射不要使用toString方法,否则会造成栈溢出错误
}
package com.li.entity;

/**
 * @author 李
 * @version 1.0
 */
public class Pet {
    private Integer id;
    private String nickname;
    //一个pet对应一个user对象
    private User user;
    
	//setter、getter方法省略
    //双向映射不要使用toString方法,否则会造成栈溢出错误
}

(2)UserMapper接口和PetMapper接口

public interface UserMapper {
    //通过id获取User对象
    public User getUserById(Integer id);
}
public interface PetMapper {
    //通过user的id获取pet对象,可能有多个因此使用集合接收
    public List<Pet> getPetByUserId(Integer userId);
}

(3)UserMapper.xml,思路:

1)先通过user_id查询得到user信息

2)再根据user_id,查询对应的pet信息,并映射到user-List< Per> pets

多对多的映射思路和一对一的实现类似,不同的使用使用resultMap映射属性时使用的是collecting标签。

<mapper namespace="com.li.mapper.UserMapper">
    <!--通过id获取User对象
        public User getUserById(Integer id);-->
    <select id="getUserById" parameterType="Integer" resultMap="resultUserMap">
        SELECT * FROM `user` WHERE id = #{id};
    </select>

    <!--User的属性映射-->
    <resultMap id="resultUserMap" type="User">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!--1.因为pets属性是一个集合,因此要使用collection标签
            2.column="id"的id是SELECT * FROM `user` WHERE id=#{id} 返回的字段
            3.ofType="Pet"指定返回的集合存放的数据类型-->
        <collection property="pets" column="id" ofType="Pet"
                    select="com.li.mapper.PetMapper.getPetByUserId"/>
    </resultMap>
</mapper>

(4)PetMapper.xml,思路和前面大体相同

<mapper namespace="com.li.mapper.PetMapper">
    <!--通过user的id获取pet对象,可能有多个因此使用集合接收
        public List<Pet> getPetByUserId(Integer userId);-->
    <select id="getPetByUserId" parameterType="Integer" resultMap="resultPetMap">
        SELECT * FROM `pet` WHERE user_id =#{userId};
    </select>

    <resultMap id="resultPetMap" type="Pet">
        <id property="id" column="id"/>
        <result property="nickname" column="nickname"/>
        <association property="user" column="user_id"
                     select="com.li.mapper.UserMapper.getUserById"/>
    </resultMap>
</mapper>

(5)测试getUserById()方法,通过UserId查找user对象和联系的pet信息

@Test
public void getUserById() {
    User user = userMapper.getUserById(2);
    System.out.println("user信息=" + user.getId() + "-" + user.getName());
    for (Pet pet : user.getPets()) {
        System.out.println("宠物信息=" + pet.getId() + "-" + pet.getNickname());
    }
    if (sqlSession != null) {
        sqlSession.close();
    }
}

测试结果:

(6)测试getPetByUserId()方法,通过user的id获取pet对象

@Test
public void getPetByUserId() {
    List<Pet> pets = petMapper.getPetByUserId(1);
    for (Pet pet : pets) {
        System.out.println("UserId=" + pet.getUser().getId()
                + "-PetId=" + pet.getId()
                + "-PetNickName=" + pet.getNickname());
    }
    if (sqlSession != null) {
        sqlSession.close();
    }
}

测试结果:

resultMap可以复用,如果有其他方法是返回的和resultMap一样的类型,可以在实现该方法时引用该resultMap。

比如PetMapper接口中新声明了一个方法:

//通过pet的id获取Pet对象,同时查询到pet对象关联的user对象
public Pet getPetById(Integer id);

PerMapper.xml文件:

<!--这里可以直接复用之前的resultPetMap-->
<select id="getPetById" parameterType="Integer" resultMap="resultPetMap">
    SELECT * FROM `pet` where id =#{id};
</select>

3.2.2方式二:注解方式

需求说明:通过注解的方式,实现双向的级联查询。

在实际开发中推荐使用配置的方式来做

(1)User和Pet实体类不变

(2)直接在接口中,通过注解实现级联查询

UserMapperAnnotation.java

package com.li.mapper;

import com.li.entity.User;
import org.apache.ibatis.annotations.*;

/**
 * @author 李
 * @version 1.0
 * 以注解的方式来实现多对一
 */
public interface UserMapperAnnotation {
    //通过id获取User对象
    @Select(value = "SELECT * FROM `user` WHERE id = #{id}")
    @Results({
            @Result(id = true, property = "id", column = "id"),
            @Result(property = "name", column = "name"),
            //这里对应返回List类型属性pets,使用注解的many属性
            @Result(property = "pets", column = "id",
                    many = @Many(select = 
                                 "com.li.mapper.PetMapperAnnotation.getPetByUserId"))
    })
    public User getUserById(Integer id);
}

PetMapperAnnotation.java

package com.li.mapper;

import com.li.entity.Pet;
import org.apache.ibatis.annotations.*;

import java.util.List;

/**
 * @author 李
 * @version 1.0
 */
public interface PetMapperAnnotation {
    //通过user的id获取pet对象
    @Select(value = "SELECT * FROM `pet` WHERE user_id =#{userId}")
    //配置了id之后就可以复用PetResuleMap
    @Results(id = "PetResuleMap", value = {
            @Result(id = true, property = "id", column = "id"),
            @Result(property = "nickname", column = "nickname"),
            @Result(property = "user", column = "user_id",
                    one = @One(select = 
                               "com.li.mapper.UserMapperAnnotation.getUserById"))
    })
    public List<Pet> getPetByUserId(Integer userId);

    
    //通过pet的id获取pet信息
    @Select(value = " SELECT * FROM `pet` where id =#{id}")
    @ResultMap("PetResuleMap")//复用上面的PetResuleMap
    public Pet getPetById(Integer id);
}

3.3练习

自己设计dept(部门)和emp(雇员)表,它们是一对多的关系。

  1. 通过查询dept,可以级联查询到所有的emp信息
  2. 通过查询emp,也可以级联查询到对应的dept信息
  3. 拓展思考:多对多关系

有关day08-MyBatis的关联映射02的更多相关文章

  1. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  2. ruby - Rails 关联 - 同一个类的多个 has_one 关系 - 2

    我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下

  3. ruby-on-rails - 复数 for fields_for has_many 关联未显示在 View 中 - 2

    目前,Itembelongs_toCompany和has_manyItemVariants。我正在尝试使用嵌套的fields_for通过Item表单添加ItemVariant字段,但是使用:item_variants不显示该表单。只有当我使用单数时才会显示。我检查了我的关联,它们似乎是正确的,这可能与嵌套在公司下的项目有关,还是我遗漏了其他东西?提前致谢。注意:下面的代码片段中省略了不相关的代码。编辑:不知道这是否相关,但我正在使用CanCan进行身份验证。routes.rbresources:companiesdoresources:itemsenditem.rbclassItemi

  4. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  5. 牛客网专项练习30天Pytnon篇第02天 - 2

    1.在Python3中,下列关于数学运算结果正确的是:(B)a=10b=3print(a//b)print(a%b)print(a/b)A.3,3,3.3333...B.3,1,3.3333...C.3.3333...,3.3333...,3D.3.3333...,1,3.3333...解析:    在Python中,//表示地板除(向下取整),%表示取余,/表示除(Python2向下取整返回3)2.如下程序Python2会打印多少个数:(D)k=1000whilek>1:    print(k)k=k/2A.1000 B.10C.11D.9解析:    按照题意每次循环K/2,直到K值小于等

  6. ruby-on-rails - Rails 中同一个类的多个关联的最佳实践? - 2

    我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来

  7. ruby-on-rails - 如何在 Rails 4 中搜索关联 - 2

    我想获取主题名称与搜索关键字匹配的所有配置文件。现在我正在加载所有配置文件。我需要知道如何实现它。非常感谢任何帮助。配置文件.rbhas_many:categorizationshas_many:subjects,through::categorizations主题.rbhas_many:categorizationshas_many:profiles,through::categorizations分类.rbbelongs_to:profilebelongs_to:subjectviews/search/index.html.erb#searchform'get'do%>nil%>#

  8. ruby-on-rails - 只有当不是 nil 时才执行映射? - 2

    如果names为nil,则以下中断。我怎样才能让这个map只有在它不是nil时才执行?self.topics=names.split(",").mapdo|n|Topic.where(name:n.strip).first_or_create!end 最佳答案 其他几个选项:选项1(在其上执行map时检查split的结果):names_list=names.try(:split,",")self.topics=names_list.mapdo|n|Topic.where(name:n.strip).first_or_create!e

  9. ruby-on-rails - 如何让 Rails View 返回其关联的操作名称? - 2

    我有一个非常简单的Controller来管理我的Rails应用程序中的静态页面:classPagesController我怎样才能让View模板返回它自己的名字,这样我就可以做这样的事情:#pricing.html.erb#-->"Pricing"感谢您的帮助。 最佳答案 4.3RoutingParametersTheparamshashwillalwayscontainthe:controllerand:actionkeys,butyoushouldusethemethodscontroller_nameandaction_nam

  10. ruby-on-rails - rails 多态关联(遗留数据库) - 2

    我使用的是遗留数据库,所以我无法控制数据模型。他们使用了很多多态链接/连接表,就像这样createtableperson(per_ident,name,...)createtableperson_links(per_ident,obj_name,obj_r_ident)createtablereport(rep_ident,name,...)其中obj_name是表名,obj_r_ident是标识符。因此链接的报告将按如下方式插入:insertintoperson(1,...)insertintoreport(1,...)insertintoreport(2,...)insertint

随机推荐