1. なぜ基底クラスで日時を管理するのか?
エンティティを使用する際に、作成日時や更新日時を追跡することはよくあります。
しかし、複数のエンティティに同じ createdAt や updatedAt プロパティを持たせると、コードが重複し保守性が低下します。
そこで基底クラス(共通の親クラス)にこれらのプロパティを持たせることで、再利用性を高めつつ、日時管理を一箇所に集約することができます。
これにより、以下のようなメリットがあります。
重複を排除: 各エンティティに createdAt や updatedAt を定義する必要がありません。
保守性向上: 日時管理のロジックを基底クラスに集約することで、修正や拡張が容易になります。
2. 基底クラスの作成手順
2.1 基底クラス BaseEntity の作成
まず、共通の親クラスとして BaseEntity を作成します。
JPA の @PrePersist と @PreUpdate を使い、エンティティが作成されるときと更新されるときに自動的に日時がセットされるようにします。
import jakarta.persistence.*; import java.time.LocalDateTime; @MappedSuperclass public abstract class BaseEntity { @Column(name = "created_at", updatable = false) private LocalDateTime createdAt; @Column(name = "updated_at") private LocalDateTime updatedAt; @PrePersist protected void onCreate() { this.createdAt = LocalDateTime.now(); this.updatedAt = LocalDateTime.now(); } @PreUpdate protected void onUpdate() { this.updatedAt = LocalDateTime.now(); } // getter メソッド public LocalDateTime getCreatedAt() { return createdAt; } public LocalDateTime getUpdatedAt() { return updatedAt; } }
各アノテーションの説明
@MappedSuperclass: このクラスは実体化されませんが、子クラスにマッピング情報が継承されます。
@PrePersist: エンティティが初めて保存されるときに呼び出され、createdAt と updatedAt に現在日時をセットします。
@PreUpdate: エンティティが更新されるときに呼び出され、updatedAt に現在日時をセットします。
2.2 エンティティで BaseEntity を継承する
作成した BaseEntity クラスを継承することで、他のエンティティでも createdAt や updatedAt の管理ができるようになります。
import jakarta.persistence.Entity; import jakarta.persistence.Table; @Entity @Table(name = "your_entity") public class YourEntity extends BaseEntity { private String name; // getter, setter など }
YourEntity には createdAt と updatedAt のフィールドが自動的に追加され、データベースに保存されるとき、または更新されるときにそれぞれの日付が設定されます。
3. 自動更新 vs 手動更新の使い分け
3.1 自動更新のメリット
通常、日時の自動更新は @PrePersist や @PreUpdate によって行われます。
リポジトリの save() メソッドを使うと、onUpdate() や onCreate() が自動で呼び出され、updatedAt や createdAt が正しく設定されます。
以下の例は自動更新の使い方です。
YourEntity entity = repository.findById(id).orElseThrow(); entity.setName("Updated Name"); // save() 時に自動で onUpdate() が呼び出され、updatedAt が更新される repository.save(entity);
3.2 手動で onUpdate() を呼び出す場合
手動で onUpdate() を呼び出すことで updatedAt を更新することも可能です。
YourEntity entity = new YourEntity(); entity.setName("New Name"); // 手動で onUpdate を呼び出す entity.onUpdate();
手動で呼び出すと意図しない更新が発生するリスクがあるため、通常は JPA の自動更新機能に任せる方が安全です。
4. まとめ
JPA の @PrePersist と @PreUpdate アノテーションを使うことで、createdAt や updatedAt を基底クラスで一元管理し、エンティティのライフサイクルに応じて自動的に日時を更新することができます。
これにより、コードの保守性が向上し、再利用可能な基盤が構築できます。
参考文献
JPA Entity Lifecycle Events
Applying @PrePersist and @PreUpdate in JPA