SpringBoot + Spring JPAで複数列の主キーをもつテーブルを検索する。

##Spring-JPAで複数列を主キーにもつテーブルについて、検索処理を試します。

1.構成

```
sample-compositepk
│  build.gradle
└─src
    ├─main
        ├─java
        │  └─com
        │      └─stone
        │          └─sample
        │                  SampleCompositePkApplication.java
        │                  SampleController.java
        │                  ServletInitializer.java
        │                  TCalendar.java
        │                  TCalendarPK.java
        │                  TCalendarRepository.java
        └─resources
            │  application.properties
            │  hibernate.properties
            │  
            ├─static
            └─templates
                    index.html
```

2.依存関係

```gradle
dependencies {
	compile('org.springframework.boot:spring-boot-starter-data-jpa')
	compile('org.springframework.boot:spring-boot-starter-thymeleaf')
	compile('org.springframework.boot:spring-boot-starter-web')
	runtime('org.springframework.boot:spring-boot-devtools')
	runtime('org.postgresql:postgresql')
	compileOnly('org.projectlombok:lombok')
	providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
	testCompile('org.springframework.boot:spring-boot-starter-test')
}
```

3.ＤＢの接続設定

```properties:application.properties
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/testdb
spring.datasource.username=testuser
spring.datasource.password=testuser
spring.jpa.hibernate.ddl-auto=none
```

```hibernate.properties
hibernate.jdbc.lob.non_contextual_creation = true
```

今回のサンプルでは、ＤＢにpostgresqlを使います。

3.ＤＢ

```sql:tcalendar.sql
create table tcalendar(
 yyyymm int not null
,dd int not null
,plans character varying(128)
,primary key(yyyymm,dd)
)
```

サンプルとして、スケジュールテーブルを作成します。
Primary Keyに、年月、日を指定してます。

```sql:insert_tcalendar.sql
insert into public.tcalendar values
(201804,1,'1日目の予定')
,(201804,2,'2日目の予定')
,(201804,3,'3日目の予定')
,(201804,4,'4日目の予定')
,(201804,5,'5日目の予定')
,(201804,6,'6日目の予定')
,(201804,7,'7日目の予定')
,(201804,8,'8日目の予定')
,(201804,9,'9日目の予定')
,(201804,10,'10日目の予定')
,(201804,11,'11日目の予定')
,(201804,12,'12日目の予定')
,(201804,13,'13日目の予定')
,(201804,14,'14日目の予定')
,(201804,15,'15日目の予定')
```
これで準備ができたので、次はアプリケーションを作成していきます。

4.Entity

```java
package com.stone.sample;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
@Entity
@Table(name="tcalendar")
@IdClass(TCalendarPK.class)
public class TCalendar {
	/**  */
	@Id
	@Column (name="yyyymm")
	private int yyyymm;
	/**  */
	@Id
	@Column (name="dd")
	private int dd;

	/**  */
	@Column (name="plans")
	private String plans;
// setter,getter
}
```

point 
@IdClassで、PrimaryKeyを定義したクラスを指定します。

5.Composite PrimaryKeyクラス

```java:TCalendarPK.java
package com.stone.sample;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class TCalendarPK implements Serializable {
	@Column (name="yyyymm")
	private int yyyymm;
	@Column (name="dd")
	private int dd;
//以下、省略
//setter, getter
//hashcode,equalsメソッド
}
```

setter, getter,hashcode,equalsメソッドは、eclipseを右クリックしてソースを選択
したら自動で作成できます。

6.Repository

```java:TCalendarRepository.java
package com.stone.sample;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface TCalendarRepository extends JpaRepository<TCalendar, TCalendarPK>{
	@Query("select o from TCalendar o where o.yyyymm = :yyyymm and o.dd = :dd")
	TCalendar findByCompositePrimaryKey(@Param("yyyymm")int yyyymm,@Param("dd")int dd);
}
```

7.Controller

```java:SampleController.java
package com.stone.sample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class SampleController {

	@Autowired
	TCalendarRepository repository;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String index(Model model) {
    	TCalendar entity = repository.findByCompositePrimaryKey(201804, 5);
    	model.addAttribute("entity", entity);
        return "index";
    }
}
```

8.HTML

```html:index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
	<head>
		<title>Hello</title>
		<meta charset="utf-8" />
		<style>
		table {border: solid 1px #000000; border-collapse: collapse;}
		</style>
	</head>
	<body>
		<h1>Springboot JPA Sample(Composite primary key)</h1>
		<table border="1">
			<thead>
				<tr>
					<td>年月</td>
					<td>日</td>
					<td>予定</td>
				</tr>
			</thead>
			<tbody>
				<tr >
					<td th:text="${entity.yyyymm}"></td>
					<td th:text="*{entity.dd}"></td>
					<td th:text="*{entity.plans}"></td>
				</tr>
			</tbody>
		</table>
	</body>
</html>
```

以上で実装完了

9.実行して確認してみます。
プロジェクトを右クリック→「実行」→「Spring boot アプリケーション」を選択します。
http://localhost:8080/
にアクセスすると、以下のような画面が表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/246741/e9dd1bdc-e55e-8f85-1823-226c4a7a4f4f.png)


以上です