Entityクラスとは?データベースのテーブルをJavaで表現する仕組み
新人
「先輩、Springでデータベースを扱うときにEntityクラスってよく出てくるんですが、そもそも何なんですか?」
先輩
「Entityクラスは、データベースのテーブルをJavaで表現するためのクラスなんだよ。テーブルの各列がJavaのフィールドになるんだ。」
新人
「なるほど。でも、なんでわざわざそんなことをするんですか?」
先輩
「それにはちゃんと理由があるよ。じゃあ、Entityクラスの役割と、なぜ必要なのかを順番に説明していこう。」
1. Entityクラスとは?
Entityクラスとは、データベースのテーブル構造をJavaのクラスとして表現するための仕組みです。Springなどのフレームワークでは、JPA(Java Persistence API)を使って、このEntityクラスと実際のデータベーステーブルを自動的にマッピングします。
例えば、社員情報を管理するemployeeというテーブルがあれば、それに対応するEmployeeというJavaクラスを作ります。そして、このクラスに@Entityアノテーションを付けることで、JPAに「これはデータベースのテーブルと対応しているクラスだよ」と伝えることができます。
基本的なEntityクラスのサンプルは以下のようになります。
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class Employee {
@Id
private Long id;
private String name;
private String department;
// getter・setterは省略
}
このように、@Entityを付けることで、このクラスがデータベースのテーブルと対応していることを示します。@Idは主キーを表し、nameやdepartmentといったフィールドは、それぞれテーブルのカラム(列)に対応します。
2. なぜEntityクラスが必要なのか?
Entityクラスは、Javaのオブジェクトとデータベースのテーブルの橋渡しをするために存在します。これをO/Rマッピング(オブジェクト・リレーショナル・マッピング)と呼びます。
Spring MVCでは、ユーザーから受け取ったデータをJavaオブジェクトとして扱い、処理が終わったらその結果をまたデータベースに保存するという流れがよくあります。そのときに、Javaとテーブルの構造が一致していれば、データの変換を簡単に行えます。
Entityクラスがない場合、SQLを手書きしてMapやListで管理する必要がありますが、それはとても煩雑でエラーが起きやすくなります。Entityを使えば、型安全かつ簡潔にデータを扱えるのです。
たとえば、以下のようなControllerクラスをSpring MVCで定義する場合、Entityクラスを使うことで入力フォームから受け取ったデータをそのまま使えます。
@Controller
public class EmployeeController {
@PostMapping("/register")
public String register(Employee employee) {
// 受け取ったEmployeeオブジェクトを保存処理に渡すなど
return "register-success";
}
}
このように、Spring MVCの@ModelAttributeのような仕組みと組み合わせて使えるのも、Entityクラスの大きな利点です。
また、データベースのテーブルが変更されたときも、Entityクラスを修正すれば対応できるため、保守性が高くなるというメリットもあります。
さらに、JPAを使えば、Entityクラスだけでテーブルの作成・更新もできるため、SQL文を書く頻度を大幅に減らせます。
3. Entityクラスの基本構造とアノテーションの意味
SpringでEntityクラスを作成する際には、いくつかの重要なアノテーションを使います。代表的なのは@Entity、@Id、@Columnです。これらを使って、Javaとデータベースの構造をマッピングします。ここでは、それぞれの役割と使い方をやさしく解説していきます。
@Entityは、このクラスがデータベースのテーブルに対応することを示します。Springがこのクラスをテーブルとして扱うためには、このアノテーションが必須です。
@Idは、テーブルの中で「主キー(プライマリーキー)」として使われる項目に付けます。主キーは、レコード(行)を一意に識別するためのものです。
@Columnは、Javaのフィールドがデータベースのカラムに対応していることを示し、カラム名や制約を指定することもできます。省略可能ですが、明示的に書いておくと可読性が上がります。
これらを組み合わせたEntityクラスの例を見てみましょう。
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Column;
@Entity
public class Product {
@Id
private Long id;
@Column(name = "product_name", nullable = false)
private String name;
@Column(name = "price")
private int price;
}
@Columnには、name属性でデータベース側のカラム名を指定でき、nullable = falseとすれば「このカラムはNULLを許容しない」ことを明示できます。
このように、Entityクラスのアノテーションは、Javaクラスとテーブル構造をしっかり対応させるためにとても重要です。特に初心者のうちは、@Columnを省略せずに書いておくと、SQLとの対応が理解しやすくなります。
この例で言えば、Productというテーブルにid、product_name、priceという3つのカラムがあることになります。
4. Entityクラスとデータベースのテーブルの対応関係
Entityクラスを作成すると、それがそのままデータベースのテーブルと1対1の関係になります。これはSpringの中でJPAが処理してくれるおかげです。開発者はJavaコードを書くだけで、テーブルの構造を作ったり読み取ったりできるようになります。
たとえば、以下のようなEntityクラスを定義したとしましょう。
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Column;
@Entity
public class Customer {
@Id
private Long id;
@Column(name = "customer_name", nullable = false)
private String name;
@Column(name = "email")
private String email;
}
このクラスをもとにテーブルを作ると、id、customer_name、emailという3つのカラムを持ったcustomerテーブルが自動的に用意されます。
pleiadesでGradleプロジェクトを作成して、SpringのJPA関連の依存関係を追加すれば、Entityクラスを作るだけでテーブルが自動的に用意されるようになります。これは自動マッピングと呼ばれる仕組みで、初心者にとって非常にありがたいポイントです。
また、テーブル名を変更したい場合には、@Tableアノテーションを使います。デフォルトではクラス名がそのままテーブル名になりますが、明示的に指定することもできます。
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Column;
@Entity
@Table(name = "user_master")
public class User {
@Id
private Long id;
@Column(name = "username")
private String name;
}
この例では、Javaのクラス名はUserですが、テーブル名はuser_masterになります。このように、クラスとテーブル名を別にしたいときには@Tableを使うと便利です。
なお、Springでこのようなマッピングを行うには、正しいパッケージ構成と、@ComponentScanや@EntityScanの設定が必要になりますが、これはSpring Bootを使わない場合でも同じです。
ここまでで、Entityクラスとテーブルがどのように対応しているのか、またアノテーションによって細かく制御できることが理解できたと思います。
次のステップでは、実際のデータの保存や読み込みについても見ていくと、よりEntityクラスの活用が理解しやすくなるでしょう。
5. Entityクラスの具体例とテーブル作成の関係(Spring Boot未使用)
Spring Bootを使わず、通常のSpring環境でEntityクラスを定義してテーブルと連携させるには、いくつかの準備が必要です。まず、GradleでJPAとJDBC関連の依存関係を追加し、データベース接続設定をpropertiesファイルに記述します。そのうえで、Entityクラスを定義すれば、アプリ起動時に自動でテーブルが作成されます。
例えば、以下のような「注文情報」を扱うEntityクラスを定義することで、対応するテーブルが作成されます。
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Column;
@Entity
public class Order {
@Id
private Long id;
@Column(nullable = false)
private String item;
@Column
private int quantity;
@Column
private String customer;
}
このEntityクラスをもとに、orderという名前のテーブルが自動で生成されます。Spring Bootではなくても、適切なEntityManagerFactoryとTransactionManagerをJavaConfigやXMLで設定すれば同様に動作します。
テーブル作成の挙動は、spring.jpa.hibernate.ddl-autoの設定値によって変わりますが、Boot未使用の場合は、Hibernateの設定ファイルでコントロールします。初心者のうちはcreateやupdateなどの設定でテーブルを自動生成する方法を試してみるのがおすすめです。
6. リレーションの簡単な紹介(@OneToMany・@ManyToOne)
Entityクラスが複数存在すると、それぞれの間に関係(リレーション)を持つことがあります。リレーションを定義することで、複数のテーブル間のつながりをJavaコード上で表現できます。
代表的なのは、以下の2つのアノテーションです。
- @OneToMany:1つの親に対して、複数の子がある(例:1人の顧客が複数の注文を持つ)
- @ManyToOne:複数の子に対して、1つの親がある(例:複数の注文が1人の顧客に属する)
以下は、簡単なリレーションの例です。顧客と注文をEntityクラスで定義し、@ManyToOneで「注文は顧客に属する」という関係を表現しています。
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
@Entity
public class Order {
@Id
private Long id;
private String item;
@ManyToOne
private Customer customer;
}
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import java.util.List;
@Entity
public class Customer {
@Id
private Long id;
private String name;
@OneToMany(mappedBy = "customer")
private List<Order> orders;
}
このように、Javaクラス間の参照でテーブル同士の関係を定義できるのが、Entityの魅力です。ただしリレーションを使うと、無限ループのようなエラーや、テーブルの作成順に依存した問題も起こるため、最初はシンプルな定義から始めましょう。
本格的なリレーション設計やFetchType、CascadeTypeなどは別の記事で解説しますが、ここでは「Entity間の関係はアノテーションで簡単に定義できる」という感覚だけ掴めば大丈夫です。
7. Entityクラスを使う際の注意点やよくある失敗例
初心者がEntityクラスを使うときによくあるつまずきポイントがあります。ここでは、特に注意しておきたいポイントをいくつか紹介します。
① @Idがないとエラーになる
Entityクラスには必ず@Idが必要です。主キーを定義しないと、JPAが「このクラスのどのフィールドを主キーとして扱うのか」がわからず、起動時にエラーになります。
② getter/setterがないと動作しないことがある
JPAは、基本的にフィールドではなく、getterとsetterを通じて値を操作します。そのため、フィールドだけを定義してgetter/setterを省略してしまうと、データの保存や取得が正常に行えないケースがあります。
③ アノテーションの綴りミスに注意
@Entityや@Columnなどのアノテーションは、綴りを少しでも間違えると、ビルドは通っても実行時にエラーになる場合があります。特に、@Tableや@GeneratedValueのような複雑なアノテーションは、構文を正しく覚えておきましょう。
④ リレーションにおける双方向参照の落とし穴
@OneToManyと@ManyToOneを両方使うと、Entity同士がお互いを参照し合って無限ループになることがあります。これは特にJSON出力時に多く、初心者が最も混乱しやすいポイントです。
⑤ フィールド名とテーブルのカラム名が一致しない場合
Javaのフィールド名とテーブルのカラム名を変える場合、@Column(name = "xxx")で正しくマッピングしないと、データが正しく読み込まれないことがあります。
これらの失敗例は、最初のうちは避けにくいですが、エラーメッセージをよく読んで1つずつ原因を確認することが重要です。慣れてくれば自然と回避できるようになるので、焦らずコツコツ学んでいきましょう。