MyBatis 映射对象关系举例(4)

many2many

many2many也是比较常见的对象关系。在这里使用Student和Teacher对象来完成双向的many2many。对象设计如下:

//学生对象
public class Student {
    private Long id;
    private String name;
    private List<Teacher> teachers = new ArrayList<Teacher>();
    //getter & setter
}
        
//教师对象
public class Teacher {
    private Long id;
    private String name;
    private List<Student> students = new ArrayList<Student>();
    //getter & setter
}
many2many关系在数据表中需要第三方的中间表参与。而在处理many2many关系的时候,需要自己手动处理中间表的数据。中间表关系需要一对student+teacher参与才能完成保存操作。在mybatis中,一是可以采用map的方式来完成中间表的映射,但是用map的使用是类型不安全的,所以,更多的,是为中间表创建一个中间对象:
//映射中间表对象,只是用来做保存和查询使用
public class StudentTeacher {
private Long studentId;
private Long teacherId;
public StudentTeacher(Long studentId, Long teacherId) {
            super();
            this.studentId = studentId;
this.teacherId = teacherId;
    }
    //getter & setter
}
many2many双方的映射都是相同的,但是需要巧用中间对象的映射,而且需要注意对象的保存顺序,废话不多说,看映射文件:
<mapper namespace="cd.itcast.mybatis.many2many.StudentMapper">
        <insert id="save" keyProperty="id" parameterType="Student"
                useGeneratedKeys="true">
         INSERT INTO student(name) values (#{name})
        </insert>
        <resultMap type="Student" id="studentmap">
        <id column="id" property="id"/>
        <result column="name" property="name"/>             
        <collection property="teachers" column="id" ofType="Teacher">
        <id property="id" column="t_id"/>
        <result property="name" column="t_name"/>
</collection>
</resultMap>
<select id="get" parameterType="long" resultMap="studentmap">
         SELECT s.*,t.name as t_name,t.id as t_id FROM student s join student_teacher st on s.id = st.student_id join teacher t on t.id = st.teacher_id WHERE s.id = #{id}
    </select>
<select id="list" resultMap="studentmap">
            SELECT s.*,t.name as t_name,t.id as t_id FROM student s join student_teacher st on s.id = st.student_id join teacher t on t.id = st.teacher_id
    </select>
<delete id="delete" parameterType="long">
            DELETE FROM student WHERE id = #{id}
        </delete>
</mapper>

<mapper namespace="cd.itcast.mybatis.many2many.TeacherMapper">
    <insert id="save" keyProperty="id" parameterType="Teacher"
                useGeneratedKeys="true">
            INSERT INTO teacher(name) values (#{name})
    </insert>
<insert id="saveRelation" parameterType="StudentTeacher">
            INSERT INTO     student_teacher(student_id,teacher_id) VALUES (#{studentId},#{teacherId})
    </insert>
<resultMap type="Teacher" id="teachermap">
<id property="id" column="id"/>
            <result property="name" column="name"/>
            <collection property="students" column="id" ofType="Student">
                   <id property="id" column="s_id"/>
                    <result property="name" column="s_name"/>
            </collection>
    </resultMap>

<select id="get" parameterType="long" resultMap="teachermap">
            SELECT t.*,s.name as s_name,s.id as s_id FROM teacher t join student_teacher st on t.id = st.teacher_id join student s on s.id = st.student_id WHERE t.id = #{id}
    </select>
        
<select id="list" resultMap="teachermap">
            SELECT t.*,s.name as s_name,s.id as s_id FROM teacher t join student_teacher st on t.id = st.teacher_id join student s on s.id = st.student_id
    </select>

<delete id="delete" parameterType="long">
            DELETE FROM teacher WHERE id = #{id}
    </delete>
        
<delete id="deleteRelation" parameterType="StudentTeacher">
            <if test="studentId != null">
                    DELETE FROM student_teacher WHERE student_id = #{studentId}
            </if>
            <if test="teacherId != null">
                    DELETE FROM student_teacher WHERE teacher_id = #{teacherId}
            </if>      
</delete>
</mapper>

上面的映射文件很明确,有几个比较重要的点需要注意:
第一,都采用内联的映射,而且都没有完成循环映射。具体的原因看上面的one2many/many2one
第二,TeacherMapper中完成对中间表对象的保存和关系的删除,注意在保存和删除时候的顺序
第三,在删除关系映射中,使用判断来确定当前删除的是teacher还是student,根据关联对象的属性值,来确定删除的SQL
来看测试,在测试代码之前,为两个映射创建对应的Mapper接口:

public interface StudentMapper {
void save(Student s);
Student get(Long id);
List<</span>Student> list(RowBounds rb);
void delete(Long id);
}

public interface TeacherMapper {
    void save(Teacher t);
    void saveRelation(StudentTeacher st);
    Teacher get(Long id);
    List<</span>Teacher> list(RowBounds rb);
    void delete(Long teacherId);
    void deleteRelation(StudentTeacher st);
}
来看看测试:

@Test
public void testSave() {
    //创建Student对象
    Student s = new Student();
    s.setName("s");
    //创建Teacher对象
    Teacher t = new Teacher();
    t.setName("t");
    //处理Student和Teacher的关系
    s.getTeachers().add(t);
    t.getStudents().add(s);
    //得到对应的Mapper接口
    SqlSession session = MyBatisUtil.openSession();
    StudentMapper smapper = session.getMapper(StudentMapper.class);
    TeacherMapper tmapper = session.getMapper(TeacherMapper.class);
    //分别保存Teacher和Student实例
    smapper.save(s);
    tmapper.save(t);
    //在保存完对象之后,需要创建中间表对象。注意顺序。
    StudentTeacher st = new StudentTeacher(s.getId(), t.getId());
    //保存中间表对象
    tmapper.saveRelation(st);
    session.commit();
    session.close();
}

@Test
public void testGet() {
    SqlSession session = MyBatisUtil.openSession();
    StudentMapper mapper = session.getMapper(StudentMapper.class);
    Student s = mapper.get(2l);
    System.out.println(s.getName());
    List<</span>Teacher> teachers = s.getTeachers();
    for (Teacher t : teachers) {
            System.out.println(t.getName());
    }
    session.close();
}

@Test
public void TestDeleteStudent(){
    SqlSession session=MyBatisUtil.openSession();
    //要删除Student必须先删除中间表和该Student有关系的数据
    StudentTeacher st=new StudentTeacher(2l,null);
    //获得TeacherMapper接口
    TeacherMapper tmapper=session.getMapper(TeacherMapper.class);
    //删除关系
    tmapper.deleteRelation(st);
    //获得StudentMapper接口
    StudentMapper smapper=session.getMapper(StudentMapper.class);
    //删除Student
    smapper.delete(2l);
    session.commit();
    session.close();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值