データベースを操作するRepositoryの作成-SpringBoot入門⑥

SpringBoot(Todo):サムネイル画像6 Todoアプリ(SpringBoot)

前回は SQL テーブルに対応する Entity を作成しました。

今回はデータベースを操作する Repository を作成します。

SpringBootでTodo開発:システム構成図1
システム構成図

Repository とは?

データベースを操作するファイルです。

実際に SQL 文を実行して、データの参照・登録・更新・削除といった、いわゆる CRUD 処理を実装していきます。

Service から呼び出され、処理結果を Service に返却します。

第3回「開発スタイルの解説」と同じことを言ってます。

なお、「Repository」と「リポジトリ」で2つの記載方法がありますが、どちらも同じ意味です。

英語表記か日本語表記かの違いだけなので。

Repository 作成

作成するリポジトリ(Repository)ファイルは全部で、

  1. AuthorityRepository
  2. CategoryRepository
  3. TodoCategoryRepository
  4. TodoRepository
  5. UserRepository

の5つです。

SpringBootでToDo開発6:各 Repository ファイルを作成
repository フォルダ内に5つ作成

repository フォルダ内に上記5つのファイルを作成してください。

各Repositoryの内容

これまでに作成した下記3つを見ながら Repository ファイルの中身を書いていきます。

  • 第3回で作成した SQL テーブル
  • 第5回で作成したエンティティ
  • 第2回で作成した以下の ER 図
2_userPK`user_id` bigint unsigned NOT NULL AUTO_INCREMENTFK`authority_id` int unsigned NOT NULL `name` varchar(16) NOT NULLUK`email` varchar(32) NOT NULL`password` varchar(32) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP3_todoPK`todo_id` bigint unsigned NOT NULL AUTO_INCREMENTFK`user_id` bigint unsigned NOT NULLUK`title` varchar(32) NOT NULL`is_check` tinyint(1) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP1_authorityPK`authority_id` int unsigned NOT NULL AUTO_INCREMENTUK`name` varchar(16) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP1_cateoryPK`category_id` int unsigned NOT NULL AUTO_INCREMENTUK`name` varchar(16) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP4_todo_categoryPK`todo_category_id` bigint unsigned NOT NULL AUTO_INCREMENTFK`todo_id` bigint unsigned NOT NULLFK`category_id` int unsigned NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

説明の都合上、作成順序は簡単なファイルからにしたいので、

  1. CategoryRepository
  2. TodoCategoryRepository
  3. AuthorityRepository
  4. TodoRepository
  5. UserRepository

の順番で作成します。

CategoryRepository

水色が第3回で作成した SQL テーブルです。

緑色が第5回で作成したエンティティです。

紫色が今回作成するリポジトリです。

-- カテゴリー情報
CREATE TABLE `category`
(
    `id`         bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'カテゴリーID',
    `name`       varchar(16) NOT NULL COMMENT 'カテゴリー名',
    `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
    `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
    PRIMARY KEY (`id`),
    UNIQUE (`name`)
) ENGINE=InnoDB
package com.ozack.todoapp.repository.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

/* カテゴリー情報 */
@Entity
@Table(name = "category")
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class Category {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

}
package com.ozack.todoapp.repository;

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

import com.ozack.todoapp.repository.entity.Category;

/* カテゴリー情報を格納している category テーブルと対応 */
@Repository
public interface CategoryRepository extends JpaRepository<Category, Long> {
}

何も書いてないじゃんって絶対思われますが、これで問題ないです。

CategoryRepository は JpaRepository を継承しているからです。

JpaRepository について

下記のCRUD機能がデフォルトで用意されている Repository です。

  1. データの登録
  2. データの取得
  3. データの更新
  4. データの削除

Jpa は環境構築時で既にインストールしています。

これらCRUD機能を継承という形で呼び出すことで使用します。

public interface CategoryRepository extends JpaRepository<Category, Long>

引数には Category エンティティと、Category エンティティの主キーである id の型を設定しています。

第一引数には、操作するテーブルに対応するエンティティ名を指定。

第二引数には、エンティティの主キーの型を指定。

と覚えておけばいいです。

必要な処理

下記4つの処理が必要です。

  1. 全カテゴリーを取得
  2. 新規カテゴリーの登録
  3. 既存カテゴリーの変更
  4. 既存カテゴリーの削除

カテゴリーデータの取得は、フロントエンド側でカテゴリーを一覧表示するため必要です。

なお、これら CRUD 機能は JpaRepository がデフォルトで用意しているので、追加でクエリ処理を記載する必要はないです。

故に、JpaRepository の継承以外は何も書かれていない状態が完成形となります。

作成した Repository は実際に Service やテストコードから実行するのですが、その際には⬇️のように呼び出して実行します。

@Autowired
CategoryRepository categoryRepository;

/* 登録・更新データの定義 */
Category saveCategory = new Category(
    null, // 登録時はDB側で勝手に付与するので不要
    "category-name-1"
);
Category updateCategory = new Category(
    1L, // 更新時は更新対象のid(主キー値)を指定
    "update-category-name-1"
);

/* 1. フロント側で表示するカテゴリー一覧を取得 */
List<Category> Categories = categoryRepository.findAll();

/* 2. 新カテゴリーの登録 */
categoryRepository.save(saveCategory);   // 引数に設定されたエンティティのidがDBに存在しなければ登録処理,存在すれば更新処理になる。

/* 3. 既存カテゴリーの更新 */
categoryRepository.save(updateCategory); // 引数に設定されたエンティティのidがDBに存在しなければ登録処理,存在すれば更新処理になる。

/* 4. 既存カテゴリーの削除 */
categoryRepository.deleteById(1L);

ここら辺は今回の本筋ではないので、次回のテストコード作成時に再度説明します。

厳密には他にも色々用意されてるため、詳細はココで確認してもいいと思います。

TodoCategoryRepository

CategoryRepository と同様、JpaRepository を継承しているだけです。

-- todo と category のマッピング情報
CREATE TABLE `todo_category`
(
    `id`           bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'マッピングID',
    `todo_id`      bigint unsigned NOT NULL COMMENT 'TodoID',
    `category_id`  bigint unsigned NOT NULL COMMENT 'カテゴリーID',
    `created_at`   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
    `updated_at`   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
    PRIMARY KEY (`id`),
    FOREIGN KEY (`todo_id`) REFERENCES `todo`(`id`) ON DELETE CASCADE,
    FOREIGN KEY (`category_id`) REFERENCES `category`(`id`) ON DELETE CASCADE,
    UNIQUE (`todo_id`, `category_id`)
) ENGINE=InnoDB
package com.ozack.todoapp.repository.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Tolerate;

/* Todo と Category のマッピング情報 */
@Entity
@Table(name = "todo_category")
@RequiredArgsConstructor
@Getter
public class TodoCategory {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private final Long id;

    @Column(name = "todo_id")
    private final Long todoId;

    @Column(name = "category_id")
    private final Long categoryId;

    @ManyToOne(
        targetEntity = Todo.class,
        fetch = FetchType.LAZY)
    @JoinColumn(
        name = "todo_id",
        insertable = false,
        updatable = false)
    @JsonBackReference
    private Todo todo;

    @ManyToOne(
        targetEntity = Category.class,
        fetch = FetchType.LAZY)
    @JoinColumn(
        name = "category_id",
        insertable = false,
        updatable = false)
    private Category category;

    @Tolerate
    public TodoCategory(){
        this.id = null;
        this.todoId = null;
        this.categoryId = null;
    }

}
package com.ozack.todoapp.repository;

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

import com.ozack.todoapp.repository.entity.TodoCategory;

/* Todo と Category のマッピング情報を格納している todo_category テーブルと対応 */
@Repository
public interface TodoCategoryRepository extends JpaRepository<TodoCategory, Long> {
}

必要な処理

ここでは、(todo,category)のマッピング情報を管理する todo_category テーブルを操作します。

下記3つの処理が必要です。

  1. 新規マッピング情報の登録
  2. 既存マッピング情報の変更
  3. 既存マッピング情報の削除

データの取得に関しては、TodoRepository の方で、 todo_category テーブルのデータも一緒に取得する方法をとるため、この Repository では取得しません。

AuthorityRepository

ここも JpaRepository を継承しているだけです。

-- 権限情報
CREATE TABLE `authority`
(
    `id`         bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '権限ID',
    `name`       varchar(16) NOT NULL COMMENT '権限名',
    `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
    `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
    PRIMARY KEY (`id`),
    UNIQUE (`name`)
) ENGINE=InnoDB
package com.ozack.todoapp.repository.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

/* 権限情報 */
@Entity
@Table(name = "authority")
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class Authority {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

}
package com.ozack.todoapp.repository;

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

import com.ozack.todoapp.repository.entity.Authority;

/* 権限情報を格納している authority テーブルと対応 */
@Repository
public interface AuthorityRepository extends JpaRepository<Authority, Long> {
}

必要な処理

ここでは、権限情報を管理する authority テーブルを操作します。

下記3つの処理が必要です。

  1. 全権限の取得
  2. 新規権限の登録
  3. 既存権限の変更
  4. 既存権限の削除

権限データの取得に関しては、フロントエンド側の管理者サイトで権限一覧を表示するため必要です。

TodoRepository

用意されていないクエリを実行するため、追加処理を定義しています。

-- Todo 情報
CREATE TABLE `todo`
(
    `id`         bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'TodoID',
    `user_id`    bigint unsigned NOT NULL COMMENT 'ユーザーID',
    `title`      varchar(32) NOT NULL COMMENT 'やること内容',
    `is_check`   tinyint(1) NOT NULL COMMENT 'チェックの有無を示す真偽値',
    `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
    `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
    PRIMARY KEY (`id`),
    FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE,
    UNIQUE (`user_id`, `title`)
) ENGINE=InnoDB
package com.ozack.todoapp.repository.entity;

import java.util.Set;

import com.fasterxml.jackson.annotation.JsonManagedReference;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Tolerate;

/* Todo 情報 */
@Entity
@Table(name = "todo")
@RequiredArgsConstructor
@Getter
public class Todo {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private final Long id;

    @Column(name = "user_id")
    private final Long userId;

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

    @Column(name = "is_check")
    private final Boolean isCheck;

    @OneToMany(
        targetEntity = TodoCategory.class,
        mappedBy = "todo",
        fetch = FetchType.LAZY)
    @JsonManagedReference
    private Set<TodoCategory> todoCategories;

    @Tolerate
    public Todo(){
        this.id = null;
        this.userId = null;
        this.title = null;
        this.isCheck = null;
    }

}
package com.ozack.todoapp.repository;

import java.util.List;

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

import com.ozack.todoapp.repository.entity.Todo;

/* Todo を格納している todo テーブルと対応 */
@Repository
public interface TodoRepository extends JpaRepository<Todo, Long> {

    /* userId を検索キーとしてデータを取得 */
    @Query("""
        SELECT t
        FROM Todo t
        LEFT JOIN FETCH t.todoCategories tc
        LEFT JOIN FETCH tc.category c
        WHERE t.userId = :userId
        ORDER BY t.id DESC
    """)
    List<Todo> findAllByUserIdWithCategories(@Param("userId") Long userId);

}

必要な処理

Todo を操作するために、下記4つの処理が必要です。

  1. 条件に一致する Todo の取得
  2. 新規 Todo の登録
  3. 既存 Todo の変更
  4. 既存 Todo の削除

Todo の取得処理では、Todo データに加えて、設定されたカテゴリーデータも結合して取得しています。

結合順序は、ざっくり説明すると、

  1. (todo, todo_category)
  2. (todo_category, category)

といった感じで、ER図の構成に準じています。

詳細なクエリ処理は下記のとおりです。

  1. (todo, todo_category) テーブル間の (id, todo_id) カラムで結合
  2. todo_category テーブルのカテゴリーidを取得
  3. (todo_category, category) テーブル間の (category_id, id) カラムで結合
  4. category テーブルのカテゴリー名を取得

JPQL について

なお、上記のクエリ処理は JPQL で記載しています。

素の SQL でクエリ定義するネイティブモードもありますが、テーブル結合が困難になるため個人的には JPQL の方が使いやすいです。

なのですが、JPQL 自体は難しいので、なんとなくやってることが分かるようであれば後回しでいいと思ってます。

多少なりとも理解したい方はこの記事オススメです。

ちなみに、自分は後から覚えました。

事後処理について

先に UserRepository の解説を見てから閲覧することを勧めます。

今回のクエリ処理、データ形式はエンティティ(Todo)のまま返却しています。

/* userId を検索キーとしてデータを取得 */
@Query("""
    SELECT t
    FROM Todo t
    LEFT JOIN FETCH t.todoCategories tc
    LEFT JOIN FETCH tc.category c
    WHERE t.userId = :userId
    ORDER BY t.id DESC
""")
List<Todo> findAllByUserIdWithCategories(@Param("userId") Long userId);

ですが、本来ならば必要なデータを Dto に格納し、不要なデータはそぎ落とすべきです。

現状だと、返却される Todo エンティティ型のデータには重複値が存在します。

結合した Category エンティティのカテゴリー id と TodoCategory エンティティのカテゴリー id 等です。

これらの値は2つも要らないため、データ量を削減するために1つだけ残すべきなのです。

それをしない理由ですが、今回の構成だと下記問題が発生するからです。

Dto は下記で定義します。

package com.ozack.todoapp.dto.response;

import java.util.List;

import com.ozack.todoapp.repository.entity.Category;

/* フロントエンド側にレスポンスする Todo データ */
public record ResponseTodoDto(
    Long id,
    String title,
    Boolean isCheck,
    List<Category> categories
){}

Repository は下記で定義します。

これが可能なら Service 側で Dto 変換せずに済むので、非常に楽です。

/* Todo を格納している todo テーブルと対応 */
@Repository
public interface TodoRepository extends JpaRepository<Todo, Long> {

    /* userId を検索キーとしてデータを取得 */
    @Query("""
        SELECT new com.ozack.todoapp.dto.response.ResponseTodoDto(
            t.id,
            t.title,
            t.isCheck,
            new com.ozack.todoapp.repository.entity.Category( 
                c.id,
                c.name
            )
        )
        FROM Todo t
        LEFT JOIN FETCH t.todoCategories tc
        LEFT JOIN FETCH tc.category c
        WHERE t.userId = :userId
        ORDER BY t.id DESC
    """)
    List<ResponseTodoDto> findAllByUserIdWithCategories(@Param("userId") Long userId);

}

なのですが、11~14行で Category 型に変換している箇所、本来なら List<Category> 型にすべきなのでエラーです。

ならリスト型に変換すればいいじゃんってなると思いますが、JPQL 内でリスト型を定義する方法は現状ありません。

そのため、リポジトリ内で対策することは不可能になっています。

この問題をリポジトリ内で対策することは Jpa の仕様的に不可能なため、Todo エンティティの Dto 変換は Service 側で行います。

UserRepository

用意されていないクエリ処理を行うため、追加で定義しています。

コッチのクエリ処理は Dto 変換できるため、リポジトリ内で Dto にして返却します。

-- ユーザー情報
CREATE TABLE `user`
(
    `id`           bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ユーザーID',
    `authority_id` bigint unsigned NOT NULL COMMENT '権限ID',
    `name`         varchar(16) NOT NULL COMMENT 'ユーザー名',
    `email`        varchar(32) NOT NULL COMMENT 'メールアドレス',
    `password`     varchar(32) NOT NULL COMMENT 'パスワード',
    `created_at`   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
    `updated_at`   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
    PRIMARY KEY (`id`),
    FOREIGN KEY (`authority_id`) REFERENCES `authority`(`id`) ON DELETE CASCADE,
    UNIQUE (`email`)
) ENGINE=InnoDB
package com.ozack.todoapp.repository.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Tolerate;

/* ユーザー情報 */
@Entity
@Table(name = "user")
@RequiredArgsConstructor
@Getter
public class User {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private final Long id;

    @Column(name = "authority_id")
    private final Long authorityId;

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

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

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

    @ManyToOne(
        targetEntity = Authority.class,
        fetch = FetchType.LAZY)
    @JoinColumn(
        name = "authority_id",
        insertable = false,
        updatable = false)
    private Authority authority;

    @Tolerate
    public User(){
        this.id = null;
        this.authorityId = null;
        this.name = null;
        this.email = null;
        this.password = null;
    }

}
package com.ozack.todoapp.repository;

import java.util.Optional;

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

import com.ozack.todoapp.dto.response.ResponseUserDto;
import com.ozack.todoapp.repository.entity.User;

/* ユーザー情報を格納している user テーブルと対応 */
@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    /* メールアドレスを検索キーとしてユーザー情報を取得 */
    @Query("""
        SELECT new com.ozack.todoapp.dto.response.ResponseUserDto(
            u.id,
            u.name,
            u.email,
            new com.ozack.todoapp.repository.entity.Authority(
                a.id,
                a.name
            )
        )
        FROM User u
        LEFT JOIN u.authority a
        WHERE u.email = :email
            """)
    Optional<ResponseUserDto> findByEmailWithAuthority(@Param("email") String email);

}

Dto について

不要なデータを排除して、都合のいい値のみを残すための型定義ファイルです。

今回の構成だと、User エンティティではパスワードを管理していますが、これはフロント側に渡すべきではありません。

そのため、パスワードを削ぎ落とすために都合のいい型を定義します。

SpringBootでToDo開発6:UserDto を作成
dto/responseフォルダ内に配置

なお、このファイルは必要なので作成しましょう。

dto/response フォルダを作成して、その中に ResponseUserDto.java ファイルを生成してください。

その上の ResponseTodoDto.java は次回で使用するため無視でいいです。

コード内容に関しては下記を写経してください。

package com.ozack.todoapp.dto.response;

import com.ozack.todoapp.repository.entity.Authority;

/* フロントエンド側にレスポンスする User データ */
public record ResponseUserDto(
    Long id,
    String name,
    String email,
    Authority authority
){}

この Dto が保持するデータは下記のとおりです。

  • ユーザーID
  • ユーザー名
  • メールアドレス
  • 権限ID
  • 権限名

権限情報は Authority エンティティ型として定義しています。

また、Dto はレコードで定義します。

基本的にクラスと同じ使い方ですが、get+変数名の形で値を取得しない点が異なります。

ResponseUserDto record = new ResponseUserDto(
    1L,
    "user-name-1",
    "user-email-1",
    new Authority( // ココはクラス定義
        1L,
        "authority-name-1"
    )
);

/* レコードから各変数値を取得 */
record.id();
record.name();
record.email()
record.Authority.getId();
record.Authority.getName();

今回の Todo 開発では最低限コレくらいの知識があれば問題ないです。

以下の記事の方は詳細まで解説されているため、より深く知れるかと。

参考になりました。

9.1 レコードクラス~Java Advanced編 - Qiita
はじめに自己紹介皆さん、こんにちは、斉藤賢哉と申します。私はこれまで、25年以上に渡って企業システムの開発に携わってきました。特にアーキテクトとして、ミッションクリティカルなシステムの技術設計や…

必要な処理

下記4つの処理が必要です。

  1. 条件に一致する Todo の取得
  2. 新規 Todo の登録
  3. 既存 Todo の変更
  4. 既存 Todo の削除

マイページ・ログイン・新規登録・名前変更・退会処理で使います。

条件(メールアドレス)に一致する Todo データの取得処理は用意されていないため、クエリ処理を追加しています。

/* メールアドレスを検索キーとしてユーザー情報を取得 */
@Query("""
    SELECT new com.ozack.todoapp.dto.response.ResponseUserDto(
        u.id,
        u.name,
        u.email,
        new com.ozack.todoapp.repository.entity.Authority(
            a.id,
            a.name
        )
    )
    FROM User u
    LEFT JOIN u.authority a
    WHERE u.email = :email
        """)
Optional<ResponseUserDto> findByEmailWithAuthority(@Param("email") String email);

なお、権限情報に関して、user テーブルは authority_id しか保持していないため、

  • (user, authority) テーブル間の (authority_id, id) カラム

で結合処理を行い権限情報を取得しています。

返却値は Optional 型にしておきます。

Optional は、検索結果が0である可能性が存在する場合に使用します。

ログイン画面で間違えた email を入力した場合等は検索結果が0になります。

まとめ

DBテーブルの操作を担当する Repository を作成しました。

main/…/repository

  1. CategoryRepository.java
  2. TodoCategoryRepository.java
  3. TodoRepository.java
  4. UserRepository.java

main/…/dto/response

  1. ResponseUserDto.java

プロジェクト構成は GitHub にプッシュしています。

GitHub - o-zack-0390/SpringBootTodoServer: Todo データを処理するSpringプロジェクト
Todo データを処理するSpringプロジェクト. Contribute to o-zack-0390/SpringBootTodoServer development by creating an...

次回は Repository のテストコードについて解説します。

タイトルとURLをコピーしました