Entity

ビジネスロジック

EntityServiceRepositoryは、Spring Data JPAで開発するためのコンポーネントで、アプリケーションのデータベース操作やビジネスロジックを設計するのに役立ちます。

Entityとは

Entityは、データベーステーブルと対応するオブジェクトです。Springアプリケーションで必須の概念で、Entityを設計することで、データ永続化(データベース保存)を容易にできます。

ORMマッピング

SpringではEntityJPAを組み合わせて、RDBのテーブル、カラム定義やSQLクエリ実行、ORMの処理などを簡単にします。

Entity
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    @Column(unique = true)
    private String email;
    ...
}

DTO

DTO(Data Transfer Object)は、複数のオブジェクトを組み合わせたデータクラスで、アプリケーション内でデータを操作するオブジェクトです。データ処理が複雑になる場合、EntityでなくDTOで処理するのが効率的です。

Repository

Repository(リポジトリ)は、データベースへアクセスを抽象化するインターフェースで、Entityに対するデータベース操作のメソッドが用意されています。Spring Data JPAを使用したRepositoryインターフェースを定義し、基本的なCRUD操作やクエリメソッドを自動的に生成できます。

public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
}

Service

Service(サービス)は、ビジネスロジックを実装するコンポーネントです。Entity操作をRepositoryを経由して実行し、よく利用するメソッドを処理します。コントローラや他のサービスから実行することで、アプリケーションのロジックを共通化できます。

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User getUserByUsername(String username) {
        return userRepository.findByUsername(username);
    }
}

Entityクラスの基本

JPAのアノテーション

JPAにはいくつかのアノテーションが用意されています。以下は代表的なアノテーションです。

アノーテーション 説明 補足
@Entity Entity クラスの宣言
@Table Tableの設定 nameでテーブル名指定
@Column Tableのカラム設定 nameでカラム名指定
@Id 主キー GenerationType.IDENTITYを設定
@GeneratedValue 値の自動生成 Auto Increment

@Entity

クラスの前に @Entityを宣言することで、Entityを定義します。

@Entity
public class クラス名 {

}

@Table

@Tableをクラスの前に宣言するとDBテーブルを定義できます。nameプロパティにDBのテーブル名を指定します。

@Entity
@Table(name = "テーブル名")
public class クラス名 {

}
  • @Tablenameプロパティを省略した場合、Entity名からテーブルを自動認識(キャメルケース)

@Tableのプロパティ例

プロパティ 説明
name テーブル名
schema スキーマ名(名前空間) デフォルト:public
catalog カタログ名 MySQLでは無視される
uniqueConstraints UNIQUE制約 例:@UniqueConstraint(columnNames = {"email"})

@Column

テーブルカラムのデータ型に合わせたプロパティを定義し、@Column でテーブルカラム情報を設定します。

@Entity
@Table(name = "テーブル名")
public class クラス名 {
    @Column(name = "カラム名")
    private データ型 プロパティ;
}
  • @Column を指定しない場合、プロパティ名がテーブルカラム名として自動識別されます。
  • プロパティ名がパスカルケースの場合、テーブルカラム名はキャメルケースとして認識されます。

データ型

Entityのプロパティデータ型とテーブルカラムのデータ型の比較例です。

テーブルカラム Entity
VARCHAR String
Int Integer
BigInt Long
BOOLEAN、TINYINT Boolean
TEXT String

@Columnのプロパティ例

@Column のプロパティは、テーブルカラムに対する設定です。

プロパティ 説明 補足
name カラム名
nullable Null の許可 デフォルト:true
length カラムのデータサイズ 数値
unique カラムのユニーク設定 デフォルト:false
columnDefinition テーブルカラムのデータ型

@Id

テーブルのプライマリーキーは、@Id@GeneratedValue で宣言します。以下は、id カラムをプライマリーキーにした例です。

@Entity
@Table(name = "テーブル名")
public class クラス名 {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

}

Entityの作成

パッケージ作成

Entityはデータテーブルの数だけ用意する必要があるため、パッケージを作成して管理します。

entityパッケージ作成

「com.example.demo」に「entity」フォルダ(パッケージ)を作成します。

Articleクラス作成

「entity」フォルダに、Articleクラスを作成します。

entity.Article.java
package com.example.demo.entity;

public class Article {

}

Entity定義

Articleクラスに @Entity を宣言してEntityクラスとします。また、@Tableでテーブル名「articles」を明示的に指定します。

entity.Article.java
package com.example.demo.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.Table;

@Entity
@Table(name = "articles")
public class Article {

}

カラム定義

プロパティ追加

テーブルカラムにあわせて、privateでプロパティを定義します。プロパティ名の記法はパスカルケースにします。

entity.Article.java
package com.example.demo.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import java.time.LocalDateTime;

@Entity
@Table(name = "articles")
public class Article {

    private String title;
    private String body;
    private String imagePath;
    private LocalDateTime postedAt;

}

Entityとテーブルカラムの関係です。

項目 Entity テーブルカラム
タイトル title String title VARCHAR(255)
本文 body String body TEXT
画像パス imagePath String image_path VARCHAR(255)
投稿日 postedAt LocalDateTime posted_at TIMESTAMP

getter/setter追加

プロパティを追加したら、getter/setterを追加します。

entity.Article.java
...
public class Article {

    private String title;
    private String body;
    private String imagePath;
    private LocalDateTime postedAt;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body.replace("&nbsp", "\n");
    }

    public String getImagePath() {
        return imagePath;
    }

    public void setImagePath(String imagePath) {
        this.imagePath = imagePath;
    }

    public LocalDateTime getPostedAt() {
        return postedAt;
    }

    public void setPostedAt(LocalDateTime postedAt) {
        this.postedAt = postedAt;
    }

}

テーブルカラム定義

Entityの各プロパティに @Columnを追加し、テーブルカラムの定義します。

entity.Article.java
...
    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String body;
    private String imagePath;

    @Column(columnDefinition = "TIMESTAMP", nullable = false)
    private LocalDateTime postedAt;
...
  • Entity「postedAt」:LocalDateTime
  • テーブルカラム「posted_at」:TIMESTAMP

日付フォーマット

@DateTimeFormatで、日付時刻フォーマットを指定できます。patternプロパティに設定したフォーマット(YMD形式)で、Entityとテーブルカラムの間で自動変換されます。

entity.Article.java
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate date;

@DateTimeFormat(pattern = "HH:mm:ss")
private LocalTime time;

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateTime;

日付フォーマット

postedAtに日付フォーマット「yyyy-MM-dd HH:mm:ss」を設定します。

entity.Article.java
...
    @Column(columnDefinition = "TIMESTAMP", nullable = false)
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime postedAt;
...

共通カラム

idcreated_atupdated_atは、共通のテーブルカラムで利用します。毎回カラム定義するのは面倒なため、共通Entityを作成して継承するようにします。

スーパークラス作成

スーパークラス「AbstractEntity」を作成し、@MappedSuperclassで定義します。

entity.AbstractEntity.java
package com.example.demo.entity;

import jakarta.persistence.MappedSuperclass;

@MappedSuperclass
public abstract class AbstractEntity {

}

共通カラム追加

共通カラムの idcreatedAtupdatedAt プロパティを追加します。

entity.AbstractEntity.java
package com.example.demo.entity;

import jakarta.persistence.MappedSuperclass;
import java.sql.Timestamp;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@MappedSuperclass
public abstract class AbstractEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    private Timestamp createdAt;

    @Column(columnDefinition = "TIMESTAMP")
    private Timestamp updatedAt;

}
  • 「DEFAULT CURRENT_TIMESTAMP」はレコード挿入時に現在の時刻を自動設定

getter追加

プロパティの*getterを追加します。これらプロパティの値はプログラムが自動設定するため、setterは不要です。

package com.example.demo.entity;

import jakarta.persistence.MappedSuperclass;
import java.sql.Timestamp;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@MappedSuperclass
public abstract class AbstractEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    private Timestamp createdAt;

    @Column(columnDefinition = "TIMESTAMP")
    private Timestamp updatedAt;

    public Long getId() {
        return id;
    }

    public Timestamp getCreatedAt() {
        return this.createdAt;
    }

    public Timestamp getUpdatedAt() {
        return this.updatedAt;
    }

}

@PrePersistと@PreUpdate

@PrePersist

@PrePersist は、Entityがデータベースに新規作成される前に実行されるメソッドです。例えば、作成日時の設定やデータバリデーションに利用されます。

@PrePersist

@PrePersist は、Entityがデータベースに更新される前に実行されるメソッドです。例えば、更新日時の設定、データバリデーションに利用されます。

...
@MappedSuperclass
public abstract class AbstractEntity {
    ...

    //データ作成時に実行
    @PrePersist
    public void onPrePersist() {
        //作成日
        this.createdAt = new Timestamp(System.currentTimeMillis());
        //更新日
        this.updatedAt = this.createdAt;
    }

    //データ更新時に実行
    @PreUpdate
    public void onPreUpdate() {
        //更新日
        this.updatedAt = new Timestamp(System.currentTimeMillis());
    }

}

Hibernate

Hibernateとは

Hibernate(ハイバネート)は、JavaオブジェクトとRDBとの間のマッピングを提供するORMツールです。よって、SQLクエリの生成やデータベースアクセスの複雑さを抽象化し、効率的にデータベース操作ができます。

スキーマ自動更新

Hibernateの機能の1つに、EntityからDBスキーマの自動生成や更新があります。「schema.sql」のようなDDLファイルを用意せずに、データベース生成できるのがメリットです。

application.propertiesの設定変更

SQL初期化モードspring.sql.init.modeをコメントアウトまたは削除し、spring.jpa.hibernate.ddl-autoでDDL自動更新を有効にします。

application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mynews
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# spring.sql.init.mode=always
spring.jpa.hibernate.ddl-auto=update

この設定でArticleモデルクラスを元に、「articles」テーブルが自動生成されます。

entity.Article.java
...

@Entity
@Table(name = "articles")
public class Article extends AbstractEntity {

    @NotBlank(message = "タイトルを入力してください")
    @Column(nullable = false)
    private String title;

    @NotBlank(message = "本文を入力してください")
    @Column(nullable = false)
    private String body;
    private String imagePath;

    @NotNull(message = "日付を入力してください")
    @Column(name = "posted_at", columnDefinition = "TIMESTAMP", nullable = false)
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime postedAt;

    //setter & getter
    ...
}
アプリケーション起動

もしデータベースに「articles」テーブルがなければ、アプリケーション起動時に自動生成されます。

  • 設定値「update」は、テーブルとEntityと相違があればカラムなどが自動追加されます。

設定値

spring.jpa.hibernate.ddl-autoの設定値は以下のとおりです。

設定値 説明
none スキーマの自動生成や更新をしない
create アプリケーション起動時に、エンティティクラスをもとに新しいスキーマを作成
create-drop createと同様だが、アプリケーションが終了するとスキーマも削除
update アプリケーション起動時に、Entityとスキーマを比較し、変更がある場合にスキーマ更新
validate アプリケーション起動時に、Entityとスキーマを比較し、違いがある場合にエラー発生

Spring超入門