【SpringBoot入門】Spring Boot+JPAで複数テーブル結合処理

投稿者: | 2018年4月17日

SpringBootのプログラミングネタ連投で失礼します。

先日、PostgresSQL+SpringBootでDBアクセスから画面表示までの実装を行いました。

【SpringBoot入門】Spring Boot + PostgreSQLの設定・DB検索

ここでは単独テーブルを利用しています。

現実的にWebアプリケーションを構築するとなると、複数テーブルをジョインしてデータ取得を行う必要があります。今回は複数テーブルを使ったデータアクセスをやってみたいと思います。

PostgresSQLの準備

テーブル作成

--親テーブル
CREATE TABLE client (
 id SERIAL PRIMARY KEY,
 name text,
 mail text, 
 memo text
);

--子テーブル
CREATE TABLE orders (
 order_num SERIAL PRIMARY KEY,
 id int,
 order_title text
);

データ登録

--client
insert into client values(1,'山田 太郎','yamada@yama.com','大口のお取引先');
insert into client values(2,'鈴木 花子','suzuki@hanako.com','とても美人');
insert into client values(3,'田中 大輔','tanaka@daisuke.com','若くて優秀');
insert into client values(4,'伊藤 カイジ','kaizi@ito.com','負債者。お金がない。');
insert into client values(5,'大槻 ハンチョウ','hancho@kuzu.com','地下の班長');

--orders
insert into orders values(1,1,'マルゲリータ');
insert into orders values(2,1,'ビスマルク');
insert into orders values(3,1,'ポテト');
insert into orders values(4,2,'コーラ');
insert into orders values(5,2,'カレー');
insert into orders values(6,3,'ハンバーガー');
insert into orders values(7,3,'レバニラ定食');
insert into orders values(8,4,'さんま');
insert into orders values(9,4,'焼き鳥');
insert into orders values(10,5,'Tボーンステーキ');
insert into orders values(11,5,'柿ピー');
insert into orders values(12,5,'柿ピーボール');

clientテーブルに対してordersテーブルが複数ある関係です。

SQLであればを以下を投げればjoinしてレコードを取ってくることができます。

select * from client A , orders B where A.id = B.id;

SpringBootのプログラム修正

前提として先日の記事で作成したプログラムを追記しています。

【SpringBoot入門】Spring Boot + PostgreSQLの設定・DB検索

Clientエンティティモデルの修正

Clients.java

package com.example.demo;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name="client")
public class Client {

	@Id
	//@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id", unique = true, nullable = false)
	private Integer id;

	@OneToMany(cascade = CascadeType.ALL)
	private List<Orders> orders;

	@Column(name="name")
	private String name;

	@Column(name="mail")
	private String mail;

	@Column(name="memo")
	private String memo;


	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getMail() {
		return mail;
	}

	public void setMail(String mail) {
		this.mail = mail;
	}

	public String getMemo() {
		return memo;
	}

	public void setMemo(String memo) {
		this.memo = memo;
	}
}

Ordersエンティティモデルの追加

Orders.java

package com.example.demo;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;


@Entity
@Table(name="orders")
public class Orders {

	@Id
	//@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "order_num", unique = true, nullable = false)
	private Integer order_num;

	@Column(name = "order_title")
	private String order_title;

	@ManyToOne
	@JoinColumn(name = "id")
	private Client client;

	public Orders() {
		super();
		client = new Client();
	}

	public Client getClient() {
		return client;
	}

	public void setClient(Client client) {
		this.client = client;
	}

	public Integer getOrder_num() {
		return order_num;
	}

	public void setOrder_num(Integer order_num) {
		this.order_num = order_num;
	}

	public String getOrder_title() {
		return order_title;
	}

	public void setOrder_title(String order_title) {
		this.order_title = order_title;
	}


}
@JoinColumn(name = "id")

こちらのアノテーションを使うことで、テーブルの項目を指定してJoinすることができる。

Ordersリポジトリの追加

OrdersRepository.java

package com.example.demo.repositories;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import com.example.demo.Orders;

@Repository
public interface OrdersRepository extends JpaRepository<Orders, Integer> {
	@Query("select max(order_num) from Orders")
	public Integer findMaxOrderNum();
}

ここでfindMaxOrderNum()を定義しているが、こちらはOrdersの主キーのMax値を取得するもの。

Insert機能を作成したときにアノテーションだと、キーを+1して登録するって動きをどう実装したらいいかわからなかったので、力技でキーを取得している…

コントローラーの修正

package com.example.demo;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.example.demo.repositories.ClientRepository;
import com.example.demo.repositories.OrdersRepository;

@Controller
@DataJpaTest
public class PosgresSampleController {
	@Autowired
	ClientRepository repository;

	@Autowired
	OrdersRepository OrdersRepository;


	@RequestMapping(value="/",method=RequestMethod.GET)
	public ModelAndView index(
			@ModelAttribute("formModel") Client tmp ,
			ModelAndView mav) {
		mav.setViewName("index");
		Iterable<Client> list = repository.findAll();
		mav.addObject("list",list);

		return mav;
	}

	@RequestMapping(value="/",method=RequestMethod.POST)
	@Transactional
	public ModelAndView form(
			@ModelAttribute("formModel") Client tmp ,
			ModelAndView mav) {

		tmp.setId(repository.findMaxId()+new Integer(1));
		repository.saveAndFlush(tmp);
		return new ModelAndView("redirect:/");
	}

	@RequestMapping(value="/orders",method=RequestMethod.GET)
	public ModelAndView orders(
			@ModelAttribute("formModel") Orders tmp ,
			ModelAndView mav) {
		mav.setViewName("orders");
		Iterable<Orders> list = OrdersRepository.findAll();
		mav.addObject("list",list);

		return mav;
	}

	@RequestMapping(value="/orders",method=RequestMethod.POST)
	@Transactional
	public ModelAndView form(
			@ModelAttribute("formModel") Orders tmp ,
			ModelAndView mav) {

		tmp.setOrder_num(OrdersRepository.findMaxOrderNum()+new Integer(1));
		OrdersRepository.saveAndFlush(tmp);
		return new ModelAndView("redirect:/orders");
	}
}

ビューの作成

<!DOCTYPE html>
<html>
<head>
	<title>orders</title>
	<meta http-equiv="Content-Type"
		content="text/html; charset=UTF-8" />
	<style>
	h1 { font-size:18pt; font-weight:bold; color:gray; }
	body { font-size:13pt; color:gray; margin:5px 25px; }
	tr { margin:5px; }
	th { padding:5px; color:white; background:darkgray; }
	td { padding:5px; color:black; background:#e0e0ff; }
	</style>
</head>
<body>
	<h1>注文</h1>
	<h2>注文一覧</h2>
	<table>
	<tr><th>注文番号</th><th>注文内容</th><th>ID</th><th>名前</th></tr>
	<tr th:each="obj : ${list}">
		<td th:text="${obj.order_num}"></td>
		<td th:text="${obj.order_title}"></td>
		<td th:text="${obj.client.id}"></td>
		<td th:text="${obj.client.name}"></td>
	</tr>
	</table>
	<hr>
	<h2>新規注文</h2>
	<table>
	<form method="post" action="/orders" th:object="${formModel}">
	<tr><td><label for="name">ID</label></td>
		<td><input type="text" name="client"/></td></tr>
	<tr><td><label for="order_title">注文</label></td>
		<td><input type="text" name="order_title"  th:value="*{order_title}" /></td></tr>
	<tr><td><input type="submit" /></td></tr>
	</form>
	</table>

</body>
</html>

動作結果

こんな感じでテーブルを結合して取得することができました。登録についても動作しました。

JPAによるテーブルアクセスに正直慣れておらずSQLは自分で書きたいと思いもしますが、これはこれで便利な面もあるのだろうと、ひとまず続けてみようと思います。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です