[Java] JPAで1対Nで中間テーブルのあるDBをModelに落とし込む


## Table構成
usersテーブルとrolesテーブルが1対Nの関係であり、中間テーブルがある構成。
![ER.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105936/bda80a33-a07d-6f28-f12e-c5fc83279f85.png)



### users

```sql
                                  Table "public.users"
  Column  |          Type          |                        Modifiers
----------+------------------------+----------------------------------------------------------
 id       | integer                | not null default nextval('users_id_seq'::regclass)
 name     | character varying(255) | not null

Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
```

### mappings

```sql
                             Table "public.mappings"
    Column    |   Type   |                          Modifiers
--------------+----------+-------------------------------------------------------------
 id           | integer  | not null default nextval('mappings_id_seq'::regclass)
 user_id      | integer  | not null
 role_id      | integer  | not null

Indexes:
    "mappings_pkey" PRIMARY KEY, btree (id)
    "mappings_user_id_role_id_key" UNIQUE CONSTRAINT, btree (user_id, role_id)
```

### roles

```sql
                                    Table "public.roles"
    Column    |          Type          |                         Modifiers
--------------+------------------------+------------------------------------------------------------
 id           | integer                | not null default nextval('roles_id_seq'::regclass)
 name         | character varying(255) | not null

Indexes:
    "roles_pkey" PRIMARY KEY, btree (id)
```

## Model作成
### UserModel

```java:UserModel
@Getter
@Entity
@Table(name="users")
public class UserModel {
    @Id
    private Long id;
    private String name;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinTable(
        // 中間テーブル名
        name="mappings",
        joinColumns = {
           /*
            * mappings -> usersの関係を定義
            * name=mappingsテーブルのカラム名
            * referencedColumnName=usersテーブルのカラム名
            */
            @JoinColumn(name="user_id", referencedColumnName="id")
        },
        inverseJoinColumns = {
           /*
            * mappings -> rolesの関係を定義
            * name=mappingsテーブルのカラム名
            * referencedColumnName=rolesテーブルのカラム名
            */
            @JoinColumn(name="role_id", referencedColumnName="id")
        }
    )
    private List<RoleModel> roles;
```

### RoleModel

```java:RoleModel
@Getter
@Entity
@Table(name="role")
public class RoleModel {
    @Id
    private Long id;
    private String name;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinTable(
        // 中間テーブル名
        name="mappings",
        joinColumns = {
           /*
            * mappings -> rolesの関係を定義
            * name=mappingsテーブルのカラム名
            * referencedColumnName=roleテーブルのカラム名
            */
            @JoinColumn(name ="role_id", referencedColumnName ="id")
        },
        inverseJoinColumns = {
           /*
            * mappings -> usersの関係を定義
            * name=mappingsテーブルのカラム名
            * referencedColumnName=usersテーブルのカラム名
            */
            @JoinColumn(name ="user_id", referencedColumnName ="id")
        }
    )
    private List<UserModel> user;
```

## Usage

```java
public interface UserRepository extends JpaRepository<UserModel, Long> {
}

public interface RoleRepository extends JpaRepository<RoleModel, Long> {
}

public class Sample {
    private UserRepository userRepository;
    private RoleRepository roleRepository;

    public void users() {
        List<UserModel> users = userRepository.findAll();
        // usersのレコードに関連付くrolesテーブルのnameカラムの1つ目を取得
        System.out.println(users.get(0).getRoles().get(0).getName());
        // usersのレコードに関連付くrolesテーブルのnameカラムの2つ目を取得
        System.out.println(users.get(0).getRoles().get(1).getName());
    }

    public void roles() {
        List<RoleModel> role = roleRepository.findAll();
        // rolesのレコードに関連付くusersテーブルのnameカラムの1つ目を取得
        System.out.println(roles.get(0).getUsers().get(0).getName());
        // rolesのレコードに関連付くusersテーブルのnameカラムの2つ目を取得
        System.out.println(roles.get(0).getUsers().get(1).getName());
    }
}
```

## 参考
- https://gist.github.com/momotar/0f168cb5d953d519017a
- https://gist.github.com/momotar/2d7a5a4f47363d0fcd25