Skip to content

@Entityの詳細設定

JPA(Java Persistence API)における@Entityアノテーションは、Javaクラスをデータベースのテーブルに対応付けるための重要なアノテーションです。この章では、@Entityとその関連アノテーションの詳細な設定方法について解説します。

@Entityアノテーションは、クラスがJPAエンティティであることを示します。

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

@Tableアノテーションの詳細設定

Section titled “@Tableアノテーションの詳細設定”

@Tableアノテーションは、エンティティがマッピングされるテーブルの詳細を指定します。

@Entity
@Table(
name = "users", // テーブル名
schema = "public", // スキーマ名
catalog = "mydb", // カタログ名
uniqueConstraints = { // ユニーク制約
@UniqueConstraint(name = "uk_email", columnNames = {"email"})
},
indexes = { // インデックス
@Index(name = "idx_name", columnList = "name"),
@Index(name = "idx_email", columnList = "email")
}
)
public class User {
// ...
}
@Entity
@Table(
name = "orders",
indexes = {
@Index(name = "idx_user_date", columnList = "user_id,order_date"),
@Index(name = "idx_status_date", columnList = "status,order_date DESC")
}
)
public class Order {
// ...
}

@Columnアノテーションの詳細設定

Section titled “@Columnアノテーションの詳細設定”

@Columnアノテーションは、フィールドがマッピングされるカラムの詳細を指定します。

@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(
name = "user_name", // カラム名
nullable = false, // NULL許可
unique = true, // ユニーク制約
length = 100, // 文字列の長さ
precision = 10, // 数値の精度(小数点を含む桁数)
scale = 2, // 数値のスケール(小数点以下の桁数)
insertable = true, // INSERT可能か
updatable = true, // UPDATE可能か
columnDefinition = "VARCHAR(100) NOT NULL" // カラム定義(DDL生成時)
)
private String name;
@Column(
name = "email_address",
nullable = false,
unique = true,
length = 255
)
private String email;
@Column(
name = "balance",
precision = 19,
scale = 2,
nullable = false
)
private BigDecimal balance;
@Column(
name = "created_at",
nullable = false,
updatable = false, // 作成後は更新不可
columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP"
)
private LocalDateTime createdAt;
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
@Entity
public class User {
// IDENTITY: データベースの自動採番(MySQL、PostgreSQL、SQL Server)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// SEQUENCE: シーケンスを使用(Oracle、PostgreSQL)
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")
@SequenceGenerator(name = "user_seq", sequenceName = "user_sequence", allocationSize = 1)
private Long id;
// TABLE: テーブルを使用したID生成
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "user_gen")
@TableGenerator(
name = "user_gen",
table = "id_generator",
pkColumnName = "gen_name",
valueColumnName = "gen_value",
pkColumnValue = "user_id",
allocationSize = 1
)
private Long id;
// AUTO: データベースに応じて自動選択
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
@Entity
@IdClass(OrderItemId.class)
public class OrderItem {
@Id
private Long orderId;
@Id
private Long productId;
private int quantity;
}
// 複合主キー用のクラス
public class OrderItemId implements Serializable {
private Long orderId;
private Long productId;
// equals, hashCodeの実装が必要
}
// または@EmbeddedIdを使用
@Entity
public class OrderItem {
@EmbeddedId
private OrderItemId id;
private int quantity;
}
@Embeddable
public class OrderItemId implements Serializable {
@Column(name = "order_id")
private Long orderId;
@Column(name = "product_id")
private Long productId;
// equals, hashCodeの実装が必要
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(
cascade = CascadeType.ALL, // カスケード操作
fetch = FetchType.LAZY, // フェッチ戦略
orphanRemoval = true // 孤立エンティティの削除
)
@JoinColumn(
name = "profile_id", // 外部キーカラム名
referencedColumnName = "id", // 参照先のカラム名
nullable = false, // NULL許可
unique = true // ユニーク制約
)
private UserProfile profile;
}
@Entity
public class UserProfile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(mappedBy = "profile")
private User user;
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
orphanRemoval = true
)
@OrderBy("createdAt DESC") // ソート順
private List<Order> orders = new ArrayList<>();
}
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany(
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
fetch = FetchType.LAZY
)
@JoinTable(
name = "user_roles", // 中間テーブル名
joinColumns = @JoinColumn(name = "user_id"), // 自分側の外部キー
inverseJoinColumns = @JoinColumn(name = "role_id") // 相手側の外部キー
)
private Set<Role> roles = new HashSet<>();
}
@Entity
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany(mappedBy = "roles")
private Set<User> users = new HashSet<>();
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// ALL: すべての操作をカスケード
@OneToOne(cascade = CascadeType.ALL)
private UserProfile profile;
// PERSIST: 保存時のみカスケード
@OneToMany(cascade = CascadeType.PERSIST)
private List<Order> orders;
// MERGE: マージ時のみカスケード
@OneToMany(cascade = CascadeType.MERGE)
private List<Order> orders;
// REMOVE: 削除時のみカスケード
@OneToMany(cascade = CascadeType.REMOVE)
private List<Order> orders;
// REFRESH: リフレッシュ時のみカスケード
@OneToMany(cascade = CascadeType.REFRESH)
private List<Order> orders;
// DETACH: デタッチ時のみカスケード
@OneToMany(cascade = CascadeType.DETACH)
private List<Order> orders;
// 複数のカスケードタイプを指定
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Order> orders;
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// EAGER: 即座にロード(推奨されない場合が多い)
@OneToOne(fetch = FetchType.EAGER)
private UserProfile profile;
// LAZY: 遅延ロード(デフォルト、推奨)
@OneToMany(fetch = FetchType.LAZY)
private List<Order> orders;
// @EntityGraphを使用した動的なフェッチ
@OneToMany(fetch = FetchType.LAZY)
@EntityGraph(attributePaths = {"orderItems"})
private List<Order> orders;
}

バージョン管理(楽観的ロック)

Section titled “バージョン管理(楽観的ロック)”
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Version
private Long version; // 楽観的ロック用のバージョン番号
private String name;
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "street", column = @Column(name = "home_street")),
@AttributeOverride(name = "city", column = @Column(name = "home_city")),
@AttributeOverride(name = "zipCode", column = @Column(name = "home_zip_code"))
})
private Address homeAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "street", column = @Column(name = "work_street")),
@AttributeOverride(name = "city", column = @Column(name = "work_city")),
@AttributeOverride(name = "zipCode", column = @Column(name = "work_zip_code"))
})
private Address workAddress;
}
@Embeddable
public class Address {
private String street;
private String city;
@Column(name = "zip_code")
private String zipCode;
// getter/setter
}
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// ORDINAL: 序数で保存(0, 1, 2...)
@Enumerated(EnumType.ORDINAL)
private OrderStatus status;
// STRING: 文字列で保存(推奨)
@Enumerated(EnumType.STRING)
@Column(length = 20)
private OrderStatus status;
// カスタムコンバーターを使用
@Convert(converter = OrderStatusConverter.class)
private OrderStatus status;
}
public enum OrderStatus {
PENDING, PROCESSING, COMPLETED, CANCELLED
}
@Converter(autoApply = true)
public class OrderStatusConverter implements AttributeConverter<OrderStatus, String> {
@Override
public String convertToDatabaseColumn(OrderStatus status) {
if (status == null) {
return null;
}
return status.name().toLowerCase();
}
@Override
public OrderStatus convertToEntityAttribute(String dbData) {
if (dbData == null) {
return null;
}
return OrderStatus.valueOf(dbData.toUpperCase());
}
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// LocalDate: DATE型にマッピング
@Column(name = "birth_date")
private LocalDate birthDate;
// LocalTime: TIME型にマッピング
@Column(name = "login_time")
private LocalTime loginTime;
// LocalDateTime: TIMESTAMP型にマッピング
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
// ZonedDateTime: TIMESTAMP WITH TIME ZONE型にマッピング
@Column(name = "updated_at")
private ZonedDateTime updatedAt;
// カスタムコンバーターを使用
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime customDateTime;
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// @ElementCollection: 基本型やエンベッダブルのコレクション
@ElementCollection
@CollectionTable(name = "user_tags", joinColumns = @JoinColumn(name = "user_id"))
@Column(name = "tag")
private List<String> tags = new ArrayList<>();
// エンベッダブルのコレクション
@ElementCollection
@CollectionTable(name = "user_phone_numbers", joinColumns = @JoinColumn(name = "user_id"))
private List<PhoneNumber> phoneNumbers = new ArrayList<>();
// Mapのマッピング
@ElementCollection
@CollectionTable(name = "user_preferences", joinColumns = @JoinColumn(name = "user_id"))
@MapKeyColumn(name = "pref_key")
@Column(name = "pref_value")
private Map<String, String> preferences = new HashMap<>();
}
@Embeddable
public class PhoneNumber {
private String type; // HOME, WORK, MOBILE
private String number;
// getter/setter
}
// 単一テーブル継承(SINGLE_TABLE)
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "user_type", discriminatorType = DiscriminatorType.STRING)
public abstract class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
@Entity
@DiscriminatorValue("ADMIN")
public class AdminUser extends User {
private String adminLevel;
}
@Entity
@DiscriminatorValue("CUSTOMER")
public class CustomerUser extends User {
private String customerLevel;
}
// テーブルごとのクラス継承(TABLE_PER_CLASS)
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class User {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
}
@Entity
public class AdminUser extends User {
private String adminLevel;
}
// 結合テーブル継承(JOINED)
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
@Entity
@PrimaryKeyJoinColumn(name = "user_id")
public class AdminUser extends User {
private String adminLevel;
}

これらの設定を適切に組み合わせることで、データベーススキーマとJavaオブジェクトのマッピングを効率的に管理できます。プロジェクトの要件に応じて、最適な設定を選択することが重要です。