1
0

More than 1 year has passed since last update.

【Mybatis】オブジェクトを持つクラスのmapping

Last updated at Posted at 2022-09-13

はじめに

MyBatisを用いてオブジェクトを持つクラスのマッピング方法を学んだので備忘のために投稿します。

開発環境・実行環境

  • Spring Tool Suite 4 Version: 4.14.1.RELEASE
  • Spring boot 2.7.2
  • Java11
  • Marvin 3.8.4
  • PostgreSQL 11.15
  • mybatis 2.2.2

やりたいこと

  • 子を複数もつ親レコードの取得を行いたい。
  • 親レコード取得の際は、id指定で1件取得したい。
  • 後程記載するdomain ParentクラスをMyBatisでマッピングしたい。

ER図

image.png

DDL文

create table parents(
	id serial NOT NULL,
	name text NOT NULL,
	gender VARCHAR(1) NOT NULL
);

create table children(
	id serial NOT NULL,
	name text NOT NULL,
	gender VARCHAR(1) NOT NULL,
	parent_id int NOT NULL
);

実装

domain

Parent.java
package com.example.domain;

import java.util.List;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

/**
 * 親テーブル
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Parent {
	
	private int id;
	private String name;
	private int gender;
    /** 子オブジェクトを複数もつ **/
	private List<Children> children;
	
}
Children.java
package com.example.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

/**
 * 子テーブル
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Children {
	
	private int id;
	private String name;
	private int gender;
	private int parentId;

}

mapper

まずMapperを作成

ParentMapper.java
package com.example.dao;

import org.apache.ibatis.annotations.Mapper;

import com.example.domain.Parent;

@Mapper
public interface ParentMapper {
	
	/** idから親レコードを取得 **/
	public Parent findById(int id);

}

【本題】xmlファイルの作成

ParentMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.dao.ParentMapper">
<select id="findById" parameterType="int" resultType="com.example.domain.Parent" resultMap="ParentMapper">
  SELECT p.id, p.name, p.gender, c.id as children_id, c.name as children_name, c.gender as children_gender 
  FROM parents p
  LEFT JOIN children c
  ON p.id = c.parent_id
  WHERE p.id = #{id}
</select>
<resultMap id="ParentMapper" type="com.example.domain.Parent">
  <id property="id" column="id"/>
  <result property="name" column="name"/>
  <result property="gender" column="gender"/>
  <!-- collectionでchildrenをマッピングする -->
  <collection property="children" ofType="com.example.domain.Children">
    <id property="id" column="children_id"/>
    <result property="name" column="children_name"/>
    <result property="gender" column="children_gender"/>
    <result property="parentId" column="id"/>
  </collection>
</resultMap>
</mapper>

resultMap内のcollectionで、childrenをマッピングする。
propertyにはchildrenクラスのフィールド名を、columnにはSQL実行したときのカラム名を指定する。
もしchildrenが居なかった場合、LEFT JOINをしているので、nullのChildrenリストが生成される。

テスト

Childrenのリストを持ったParentオブジェクトを取得できているか確認する。

SQL

テスト用に準備したSQL

insert into parents(name, gender) values ('佐藤太郎', 1);
insert into parents(name, gender) values ('高橋花子', 2);
insert into parents(name, gender) values ('山田裕子', 2);

insert into children(name, gender, parent_id) values ('佐藤次郎', 1, 1);
insert into children(name, gender, parent_id) values ('高橋智子', 2, 2);
insert into children(name, gender, parent_id) values ('高橋達郎', 1, 2);

テストコード

ParentMapperTest.java
package com.example.dao;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;

import com.example.domain.Children;
import com.example.domain.Parent;

@MybatisTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) // 単体テストでPostgreSQLを使用するための設定
class ParentMapperTest {
	
	@Autowired
	private ParentMapper parentMapper;

	@BeforeAll
	static void setUpBeforeClass() throws Exception {
	}

	@AfterAll
	static void tearDownAfterClass() throws Exception {
	}

	@BeforeEach
	void setUp() throws Exception {
	}

	@AfterEach
	void tearDown() throws Exception {
	}

	@Test
	@DisplayName("親:高橋花子、子:高橋智子、高橋達郎 のParentオブジェクトを取得できているか")
	public void findByIdTest() {
        // parentのid
		int id = 2;
		
		// 期待値
		Children child1 = new Children(2, "高橋智子", 2, 2);
		Children child2 = new Children(3, "高橋達郎", 1, 2);
		List<Children> children = new ArrayList<>() {
			{
				add(child1);
				add(child2);
			}
		};

		Parent expected = new Parent(2, "高橋花子", 2, children);
		
        // 実際
		Parent actual = parentMapper.findById(id);
		
		// 結果
		assertEquals(expected.toString(), actual.toString());
		System.out.println(actual);
	}

}

コンソール出力結果

Parent(id=2, name=高橋花子, gender=2, 
children=[Children(id=2, name=高橋智子, gender=2, parentId=2), 
Children(id=3, name=高橋達郎, gender=1, parentId=2)])

終わりに

MyBatisのresultMapを用いてオブジェクトを持つクラスのマッピングを行いました。
間違っている部分もあるかもしれませんので、その際はご指摘頂ければと思います。

参考文献

mybatis 公式
MybatisのMapperを使った高度なマッピングー親子関係にあるテーブルの検索結果を格納するResultMap
mybatisで値オブジェクト(Value Object)を扱う場合のポイント

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0