JPAを使ってみよう
O/R Mapperを使ってみよう
前回はFlywayを使ったDB構築の自動化についてご紹介しました。
関連記事
【DBマイグレーション】GradleにFlywayを組み込んでパッチ適用を自動化しよう【SpringBoot2】
IT
Java
Mac
Windows
アプリケーション今回はJPAを利用したデータベースからの参照処理のO/R Mappingを実装してみようと思います。
JPAとは?
JPAは正式にはJava Persistence APIと呼び、Java EE標準のO/R MappingおよびDAOの技術仕様の事を指します。
Java Persistence API(JPA)とは、関係データベースのデータを扱う Java SE および Java EE のアプリケーションを開発するためのJava用フレームワークである。JPA は、以下の3つの部分から成る。
API(javax.persistence パッケージで定義されている) Java Persistence Query Language オブジェクト/関係メタデータJava Persistence API - Wikipedia
また、JPAはあくまで仕様なので実際にはEclipseLink,Hibernate ORM,Apache Open JPAなどのライブラリを使うことになると思います。
今回は、SpringBootでJPAを利用する際にデフォルトで仕様されるHibernateを使ってみようと思います。
手順
マッピングするテーブル構造
今回も前回作成したテーブル構造をベースにマッピングしていきます。

今回の目的は、ユーザー一覧を取得するためにマッピングテーブルであるcurrent_account_infomationsテーブルを軸に取得してこようと思います
今回利用するJPAアノテーション
JPAは基本的にアノテーションベースでマッピングの設定をしていきます。
今回登場するのは以下のアノテーションです。
| アノテーション | 概要 |
|---|---|
| @Column( name = {カラム名} ) | フィールドにマッピングするDBのカラム名をname属性で設定する |
| @Enumerated( EnumType.STRING ) | Enumにカラムをマッピングしたい場合に設定する |
| @Entity | テーブルと対応するEntityクラスに設定する |
| @Table( schema = {スキーマ名}, name = {テーブル名} ) | Entityクラスに紐付けたいテーブル情報を設定する |
| @EmbeddedId | PKカラムを紐付けたいクラスを参照する際に設定する |
| @Embedded | PKではないカラムを紐付けたいクラスを参照する際に設定する |
| @OneToOne | 1...1のテーブルを結合したい際に設定する ※今回はテーブル定義情報は1..1~nだが、こちらを使うことでやりたいことは実現出来た |
| @ManyToOne | N...0~1のテーブルを結合したい際に設定する |
| @JoinColumn( name = {カラム名} ) | 結合する際のFKカラム名を指定したい場合に設定する |
| @AttributeOverride(name = {上書き対象フィールド}, column = @Column(name = {上書き後の値} ) ) | 紐付けるEntity内のフィールドのカラム定義を上書きする ※今回のテーブル定義としては自テーブルと参照元によって同じコンテキストでも冗長的記述を端折るために異なるカラム名を付与しているので利用しています |
開発用afterMigrateデータ
今回はローカル開発動作確認用として、以下のデータを投入します。
期待値としてはマッピングテーブルを用いて(新)のものだけ取得出来ればOKです。
-- ####################
-- # アカウント1
-- ####################
INSERT INTO
account.accounts
(
id
) VALUES (
(SELECT nextval('account.account_id'))
);
INSERT INTO account.account_infomations
(
id,
account_id,
name,
age,
sex_type,
display_name
) values (
(SELECT nextval('account.account_infomation_id')),
(SELECT MAX(id) FROM account.accounts),
'山田 太郎',
19,
'MALE',
'山田 ローカル 太郎(古)'
);
INSERT INTO account.account_infomations
(
id,
account_id,
name,
age,
sex_type,
display_name
) values (
(SELECT nextval('account.account_infomation_id')),
(SELECT MAX(id) FROM account.accounts),
'山田 太郎',
19,
'MALE',
'山田 ローカル 太郎(新)'
);
INSERT INTO account.current_account_infomations
(
account_id,
account_infomation_id
) values (
(SELECT MAX(id) FROM account.accounts),
(SELECT MAX(id) FROM account.account_infomations)
);
-- ####################
-- # アカウント2
-- ####################
INSERT INTO
account.accounts
(
id
) VALUES (
(SELECT nextval('account.account_id'))
);
INSERT INTO account.account_infomations
(
id,
account_id,
name,
age,
sex_type,
display_name
) values (
(SELECT nextval('account.account_infomation_id')),
(SELECT MAX(id) FROM account.accounts),
'田中 花子',
20,
'FEMALE',
'田中 ローカル 花子(古)'
);
INSERT INTO account.account_infomations
(
id,
account_id,
name,
age,
sex_type,
display_name
) values (
(SELECT nextval('account.account_infomation_id')),
(SELECT MAX(id) FROM account.accounts),
'田中 花子',
20,
'FEMALE',
'田中 ローカル 花子(新)'
);
INSERT INTO account.current_account_infomations
(
account_id,
account_infomation_id
) values (
(SELECT MAX(id) FROM account.accounts),
(SELECT MAX(id) FROM account.account_infomations)
);
-- ####################
-- # アカウント3
-- ####################
INSERT INTO
account.accounts
(
id
) VALUES (
(SELECT nextval('account.account_id'))
);
INSERT INTO account.account_infomations
(
id,
account_id,
name,
age,
sex_type,
display_name
) values (
(SELECT nextval('account.account_infomation_id')),
(SELECT MAX(id) FROM account.accounts),
'山田 二郎',
15,
'NONE',
'山田 ローカル 二郎(古)'
);
INSERT INTO account.account_infomations
(
id,
account_id,
name,
age,
sex_type,
display_name
) values (
(SELECT nextval('account.account_infomation_id')),
(SELECT MAX(id) FROM account.accounts),
'山田 二郎',
15,
'NONE',
'山田 ローカル 二郎(新)'
);
INSERT INTO account.current_account_infomations
(
account_id,
account_infomation_id
) values (
(SELECT MAX(id) FROM account.accounts),
(SELECT MAX(id) FROM account.account_infomations)
);
依存関係の追加
まずはgradleの依存関係にJPAを追加していきましょう。
buildscript {
apply from: 'property.gradle'
ext {
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${accountService.springBootVersion}")
classpath "org.yaml:snakeyaml:${accountService.snakeyamlVersion}"
classpath "org.postgresql:postgresql:${accountService.postgresVersion}"
}
}
allprojects {
apply plugin: 'eclipse'
}
subprojects {
apply plugin: "java"
apply plugin: "io.spring.dependency-management"
group = accountService.group
version = accountService.version
sourceCompatibility = accountService.sourceCompatibility
repositories {
mavenCentral()
}
dependencyManagement {
}
dependencies {
implementation "org.springframework.boot:spring-boot-starter:${accountService.springBootVersion}"
implementation "org.springframework.boot:spring-boot-starter-data-jpa:${accountService.springBootVersion}" // 追加
testImplementation "org.springframework.boot:spring-boot-starter-test:${accountService.springBootVersion}"
}
}
Valueプロジェクトの修正
次にValueモデルを修正します。
package tech.blogenist.service.account.value.account;
import java.io.Serializable;
import javax.persistence.Column;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class AccountIdValue implements Serializable
{
public static final String LAVEL = "会員ID";
public static final String COLUMN_NAME = "id";
public static final String FK_COLUMN_NAME = "account_id";
@Column(
name = COLUMN_NAME )
private Integer value;
}
package tech.blogenist.service.account.value.account;
import java.io.Serializable;
import javax.persistence.Column;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class AccountInfomationIdValue implements Serializable
{
public static final String LAVEL = "会員情報ID";
public static final String COLUMN_NAME = "id";
public static final String FK_COLUMN_NAME = "account_infomation_id";
@Column(
name = COLUMN_NAME )
private Integer value;
}
package tech.blogenist.service.account.value.account;
import javax.persistence.Column;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class AccountNameValue
{
public static final String LAVEL = "会員名";
public static final String COLUMN_NAME = "name";
@Column(
name = COLUMN_NAME )
private String value;
}
package tech.blogenist.service.account.value.account;
import javax.persistence.Column;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class AgeValue
{
public static final String LAVEL = "年齢";
public static final String COLUMN_NAME = "age";
@Column(
name = COLUMN_NAME )
private Integer value;
}
package tech.blogenist.service.account.value.account;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class SexTypeValue implements Serializable
{
public static final String LAVEL = "性別";
public static final String COLUMN_NAME = "type";
public static final String FK_COLUMN_NAME = "sex_type";
@Enumerated( EnumType.STRING )
@Column(
name = COLUMN_NAME )
private Type type;
@AllArgsConstructor
public enum Type
{
NONE( "未設定" ),
MALE( "男性" ),
FEMALE( "女性" );
@Getter
private String lavel;
}
}
package tech.blogenist.service.account.value.common.datetime;
import java.time.LocalDateTime;
import javax.persistence.Column;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class CommonCreatedAtValue
{
public static final String LAVEL = "作成日時";
public static final String COLUMN_NAME = "created_at";
@Column(
name = COLUMN_NAME )
private LocalDateTime value;
}
package tech.blogenist.service.account.value.common.datetime;
import java.time.LocalDateTime;
import javax.persistence.Column;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class CommonUpdatedAtValue
{
public static final String LAVEL = "更新日時";
public static final String COLUMN_NAME = "updated_at";
@Column(
name = COLUMN_NAME )
private LocalDateTime value;
}
package tech.blogenist.service.account.value.common.datetime;
import javax.persistence.Column;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class MasterNameValue
{
public static final String LAVEL = "名称";
public static final String COLUMN_NAME = "name";
@Column(
name = COLUMN_NAME )
private String value;
}
package tech.blogenist.service.account.value.infrastructure.field;
public class ValueFieldConst
{
public static final String FIELD = "value";
}
Entityプロジェクトの修正
次にEntityモデルを修正します。
package tech.blogenist.service.account.entity.db.account;
import javax.persistence.Embedded;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import tech.blogenist.service.account.value.account.AccountIdValue;
import tech.blogenist.service.account.value.common.datetime.CommonCreatedAtValue;
import tech.blogenist.service.account.value.common.datetime.CommonUpdatedAtValue;
@Builder
@Entity
@Table(
schema = AccountsTableEntity.SCHEMA_NAME, name = AccountsTableEntity.TABLE_NAME )
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class AccountsTableEntity
{
public static final String SCHEMA_NAME = "account";
public static final String TABLE_NAME = "accounts";
@EmbeddedId
private AccountIdValue accountId;
@Embedded
private CommonCreatedAtValue createdAt;
@Embedded
private CommonUpdatedAtValue updatedAt;
}
package tech.blogenist.service.account.entity.db.account;
import javax.persistence.Embedded;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import tech.blogenist.service.account.value.account.AccountDisplayNameValue;
import tech.blogenist.service.account.value.account.AccountIdValue;
import tech.blogenist.service.account.value.account.AccountInfomationIdValue;
import tech.blogenist.service.account.value.account.AccountNameValue;
import tech.blogenist.service.account.value.account.AgeValue;
import tech.blogenist.service.account.value.account.SexTypeValue;
import tech.blogenist.service.account.value.common.datetime.CommonCreatedAtValue;
import tech.blogenist.service.account.value.common.datetime.CommonUpdatedAtValue;
@Builder
@Entity
@Table(
schema = AccountInfomationsTableEntity.SCHEMA_NAME, name = AccountInfomationsTableEntity.TABLE_NAME )
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class AccountInfomationsTableEntity
{
public static final String SCHEMA_NAME = "account";
public static final String TABLE_NAME = "account_infomations";
@EmbeddedId
private AccountInfomationIdValue accountInfomationId;
@ManyToOne
@JoinColumn(
name = AccountIdValue.FK_COLUMN_NAME )
private AccountsTableEntity accountEntity;
@Embedded
private AccountNameValue name;
@Embedded
private AgeValue age;
@ManyToOne
@JoinColumn(
name = SexTypeValue.FK_COLUMN_NAME )
private SexTypesTableEntity sexType;
@Embedded
private AccountDisplayNameValue displayName;
@Embedded
private CommonCreatedAtValue createdAt;
@Embedded
private CommonUpdatedAtValue updatedAt;
}
package tech.blogenist.service.account.entity.db.account;
import javax.persistence.Embedded;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import tech.blogenist.service.account.value.account.SexTypeValue;
import tech.blogenist.service.account.value.common.datetime.MasterNameValue;
@Builder
@Entity
@Table(
schema = SexTypesTableEntity.SCHEMA_NAME, name = SexTypesTableEntity.TABLE_NAME )
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class SexTypesTableEntity
{
public static final String SCHEMA_NAME = "account";
public static final String TABLE_NAME = "sex_types";
@EmbeddedId
private SexTypeValue type;
@Embedded
private MasterNameValue name;
}
package tech.blogenist.service.account.entity.db.account;
import javax.persistence.AttributeOverride;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import tech.blogenist.service.account.value.account.AccountIdValue;
import tech.blogenist.service.account.value.account.AccountInfomationIdValue;
import tech.blogenist.service.account.value.common.datetime.CommonCreatedAtValue;
import tech.blogenist.service.account.value.common.datetime.CommonUpdatedAtValue;
import tech.blogenist.service.account.value.infrastructure.field.ValueFieldConst;
@Builder
@Entity
@Table(
schema = CurrentAccountInfomationsTableEntity.SCHEMA_NAME,
name = CurrentAccountInfomationsTableEntity.TABLE_NAME )
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class CurrentAccountInfomationsTableEntity
{
public static final String SCHEMA_NAME = "account";
public static final String TABLE_NAME = "current_account_infomations";
@AttributeOverride(
name = ValueFieldConst.FIELD, column = @Column(
name = AccountIdValue.FK_COLUMN_NAME ) )
@EmbeddedId
private AccountIdValue accountId;
@OneToOne
@JoinColumn(
name = AccountInfomationIdValue.FK_COLUMN_NAME,
referencedColumnName = AccountInfomationIdValue.COLUMN_NAME )
private AccountInfomationsTableEntity accountInfomations;
@Embedded
private CommonCreatedAtValue createdAt;
@Embedded
private CommonUpdatedAtValue updatedAt;
}
Datasourceプロジェクトの修正
package tech.blogenist.service.account.datasource.db.current_account.account_infomations;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import tech.blogenist.service.account.entity.db.account.CurrentAccountInfomationsTableEntity;
import tech.blogenist.service.account.value.account.AccountIdValue;
@Repository
public interface CurrentAccountInfomationsRepository
extends JpaRepository< CurrentAccountInfomationsTableEntity, AccountIdValue >
{
public List< CurrentAccountInfomationsTableEntity > findAll();
}
APIプロジェクトの修正
modelパッケージ
package tech.blogenist.service.account.api.model.account.listing.response;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import tech.blogenist.service.account.value.account.AccountDisplayNameValue;
import tech.blogenist.service.account.value.account.AccountIdValue;
import tech.blogenist.service.account.value.account.AccountInfomationIdValue;
import tech.blogenist.service.account.value.account.AccountNameValue;
import tech.blogenist.service.account.value.account.AgeValue;
import tech.blogenist.service.account.value.common.datetime.MasterNameValue;
@Builder
@AllArgsConstructor(
staticName = "of" )
@NoArgsConstructor(
staticName = "empty" )
@Data
public class AccountListingElementModel
{
private AccountIdValue accountId;
private AccountInfomationIdValue accountInfomationId;
private AccountNameValue name;
private AgeValue age;
private MasterNameValue sex;
private AccountDisplayNameValue displayName;
}
package tech.blogenist.service.account.api.model.account.listing.response;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@AllArgsConstructor( staticName = "of" )
@NoArgsConstructor( staticName = "empty" )
@Data
public class AccountListingResponseModel
{
private List< AccountListingElementModel > accounts;
}
serviceパッケージ
package tech.blogenist.service.account.api.service.account.listing;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tech.blogenist.service.account.api.model.account.listing.response.AccountListingElementModel;
import tech.blogenist.service.account.api.model.account.listing.response.AccountListingResponseModel;
import tech.blogenist.service.account.datasource.db.current_account.account_infomations.CurrentAccountInfomationsRepository;
import tech.blogenist.service.account.entity.db.account.AccountInfomationsTableEntity;
import tech.blogenist.service.account.entity.db.account.CurrentAccountInfomationsTableEntity;
import tech.blogenist.service.account.value.common.datetime.MasterNameValue;
@Service
public class AccountListingService
{
@Autowired
private CurrentAccountInfomationsRepository currentAccountInfomationsRepository;
public AccountListingResponseModel listing()
{
List< CurrentAccountInfomationsTableEntity > entities = currentAccountInfomationsRepository.findAll();
List< AccountListingElementModel > elements = entities.stream()
.map( entity ->
{
AccountInfomationsTableEntity infomation = entity.getAccountInfomations();
AccountListingElementModel element = AccountListingElementModel.builder()
.accountInfomationId( infomation.getId() )
.accountId( entity.getAccountId() )
.age( infomation.getAge() )
.name( infomation.getName() )
.sex(
infomation.getSexType() == null
? MasterNameValue.empty()
: infomation.getSexType().getName() )
.displayName( infomation.getDisplayName() )
.build();
return element;
} )
.collect( Collectors.toList() );
return AccountListingResponseModel.of( elements );
}
}
package tech.blogenist.service.account.api.service.account.detail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tech.blogenist.service.account.api.model.account.detail.response.AccountDetailResponseModel;
import tech.blogenist.service.account.datasource.db.current_account.account_infomations.CurrentAccountInfomationsRepository;
import tech.blogenist.service.account.entity.db.account.CurrentAccountInfomationsTableEntity;
import tech.blogenist.service.account.value.account.AccountIdValue;
@Service
public class AccountDetailService
{
@Autowired
private CurrentAccountInfomationsRepository currentAccountInfomationsRepository;
public AccountDetailResponseModel findBy( AccountIdValue id )
{
CurrentAccountInfomationsTableEntity entity = currentAccountInfomationsRepository
.findByAccountId( id );
return AccountDetailResponseModel.builder()
.accountId( entity.getAccountId() )
.accountInfomationId( entity.getAccountInfomations().getId() )
.name( entity.getAccountInfomations().getName() )
.age( entity.getAccountInfomations().getAge() )
.displayName( entity.getAccountInfomations().getDisplayName() )
.sex( entity.getAccountInfomations().getSexType().getName() )
.build();
}
}
apiパッケージ
package tech.blogenist.service.account.api.controller.account.listing;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tech.blogenist.service.account.api.infrastructure.rest.path.RestPathConst;
import tech.blogenist.service.account.api.model.account.listing.response.AccountListingResponseModel;
import tech.blogenist.service.account.api.service.account.listing.AccountListingService;
@RestController
@RequestMapping( RestPathConst.VersionPath.V1 + RestPathConst.CategoryPath.AccountPath.BASE_PATH )
public class AccountListingController
{
@Autowired
private AccountListingService service;
@GetMapping
public AccountListingResponseModel listing()
{
AccountListingResponseModel response = service.listing();
return response;
}
}
package tech.blogenist.service.account.api.controller.account.detail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tech.blogenist.service.account.api.infrastructure.rest.path.RestPathConst;
import tech.blogenist.service.account.api.model.account.detail.response.AccountDetailResponseModel;
import tech.blogenist.service.account.api.service.account.detail.AccountDetailService;
import tech.blogenist.service.account.value.account.AccountIdValue;
@RestController
@RequestMapping( RestPathConst.VersionPath.V1 + RestPathConst.CategoryPath.AccountPath.BASE_PATH )
public class AccountDetailController
{
@Autowired
private AccountDetailService service;
@GetMapping(
path = RestPathConst.CategoryPath.AccountPath.RESOURCE_PATH )
public AccountDetailResponseModel detail(
@PathVariable( RestPathConst.CategoryPath.AccountPath.PATH_VARIABLE ) Integer accountId
)
{
AccountDetailResponseModel response = service.findBy( AccountIdValue.of( accountId ) );
return response;
}
}
動作確認
では、実際にエンドポイントを叩いてみましょう!
一覧
{
"accounts": [
{
"accountId": {
"value": 10001
},
"accountInfomationId": {
"value": 20002
},
"name": {
"value": "山田 太郎"
},
"age": {
"value": 19
},
"sex": {
"value": "男性"
},
"displayName": {
"value": "山田 ローカル 太郎(新)"
}
},
{
"accountId": {
"value": 10002
},
"accountInfomationId": {
"value": 20004
},
"name": {
"value": "田中 花子"
},
"age": {
"value": 20
},
"sex": {
"value": "女性"
},
"displayName": {
"value": "田中 ローカル 花子(新)"
}
},
{
"accountId": {
"value": 10003
},
"accountInfomationId": {
"value": 20006
},
"name": {
"value": "山田 二郎"
},
"age": {
"value": 15
},
"sex": {
"value": "未設定"
},
"displayName": {
"value": "山田 ローカル 二郎(新)"
}
}
]
}
詳細
{
"accountId": {
"value": 10001
},
"accountInfomationId": {
"value": 20002
},
"name": {
"value": "山田 太郎"
},
"age": {
"value": 19
},
"sex": {
"value": "男性"
},
"displayName": {
"value": "山田 ローカル 太郎(新)"
}
}
無事にテーブル結合が行われて、複数テーブルのデータをレスポンスモデルに変換して取得することが出来ました♪
参考
終わりに
以上のように、JPAの仕組みやマッピング方法や結合方法さえわかれば、SQLを書くことなくデータの取得が可能になります。
他にもJPAには便利な機能が搭載されていますので、是非使ってみてください♪
