About

ドキュメント

Javadoc

モジュール

プロジェクト文書

Built by Maven

概要

エンティティの定義の仕方を説明します。ここでいっているエンティティとは、 データベースに永続化されるものだと考えてください。

注意点

エンティティ用のアノテーションは、JPAのものをそのまま利用していますが、 すべてのアノテーションや属性をサポートしているわけではありません。 ここに取り上げられているもののみサポートされているとお考えください。

エンティティ定義

エンティティにするためには、 @Entity を必ず指定する必要があります。

@Entity
public class Employee {
    ...
}

name属性でエンティティ名を指定することができます。 次の例では、Empというエンティティ名を指定しています。

@Entity(name = "Emp")
public class Employee {
    ...
}

name属性を指定しなかった場合、エンティティのクラス名からパッケージ名を除いた部分が、 デフォルトのエンティティ名になります。例えば、クラス名が examples.entity.Employee の場合、デフォルトのエンティティ名は、 Employee になります。

テーブル定義

テーブル情報を指定するには、 @Table を使います。

name属性でテーブル名を指定することができます。 指定しなかった場合、テーブル名はエンティティ名と同じになります。エンティティ名が、 AaaBbb のようなキャメル記法の場合、テーブル名は、 AAA_BBB のように'_'区切りだとみなされます。

このルールは、convention.diconで指定されている org.seasar.framework.convention.impl.PersistenceNamingConventionImpl のfromEntityNameToTableName()の実装を変えることで、カスタマイズすることができます。

次の例では、EMPというテーブル名を指定しています。

@Entity
@Table(name = "EMP")
public class Employee {
    ...
}

schema属性でスキーマを指定することができます。 指定した場合、自動生成されるSQLのテーブル名がスキーマ.テーブル名になります。

catalog属性でカタログを指定することができます。 指定した場合、自動生成されるSQLのテーブル名がカタログ.テーブル名になります。 catalog属性とschema属性の両方を指定した場合、自動生成されるSQLのテーブル名はカタログ.スキーマ.テーブル名になります。

継承

エンティティは @MappedSuperclass が指定されたクラスを継承できます。

@MappedSuperclass
public abstract class AbstractEmployee {
    ...
}
@Entity
public class Employee extends AbstractEmployee {
    ...
}

@MappedSuperclass には、エンティティと同じように永続プロパティを定義できます。 定義された永続プロパティは、サブクラスの永続プロパティとみなされます。 スーパークラスとサブクラスでインスタンスフィールドの名前が重複しないように定義してください。

エンティティは @MappedSuperclass が指定されていないクラスも継承できます。 しかし、この場合、スーパークラスのプロパティはサブクラスの永続プロパティとみなされません。

エンティティが他のエンティティを継承することはサポートされていません。

プロパティ定義

永続プロパティの型

関連 および 永続化対象外 を除いたプロパティとして利用可能な型は次のとおりです。

プリミティブ型
  • boolean
  • char
  • byte
  • short
  • int
  • long
  • float
  • double
ラッパー型
  • Boolean
  • Character
  • Byte
  • Short
  • Integer
  • Long
  • Float
  • Double
文字列型
  • java.lang.String

ラージオブジェクト にすることができます。

数値型
  • java.math.BigDecimal
  • java.math.BigInteger
日付・時刻型
  • java.util.Date
  • java.util.Calendar
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp

java.util.Date および java.util.Calendar 型のプロパティには 時制 の指定が必須です.

バイト列型
  • byte[]

ラージオブジェクト にすることができます。

シリアライズ可能型
  • java.io.Serializable

ラージオブジェクト にすることができます。

カラム定義

カラム情報を指定するには、 @Column を使います。

name属性でカラム名を指定することができます。 指定しなかった場合、カラム名はフィールド名と同じになります。フィールド名が、 aaaBbb のようなキャメル記法の場合、カラム名は、 AAA_BBB のように'_'区切りだとみなされます。

このルールは、convention.diconで指定されている org.seasar.framework.convention.impl.PersistenceNamingConventionImpl のfromPropertyNameToColumnName()の実装を変えることで、カスタマイズすることができます。

デフォルトでは、プロパティ名とフィールド名は同じになりますが、convention.diconで指定されている org.seasar.framework.convention.impl.PersistenceNamingConventionImpl のfromFieldNameToPropertyName()の実装を変えることで、カスタマイズすることができます。

次の例では、AB1234というカラム名を指定しています。

@Column(name = "AB1234")
public String shortName;

insertable属性で挿入可能かどうかを指定することができます。デフォルトはtrueです。 falseの場合、挿入用のSQLにこのカラムは含まれません。 カラムにデフォルト値を適用したい場合は、falseにすると良いでしょう。

updatable属性で更新可能かどうかを指定することができます。デフォルトはtrueです。 falseの場合、更新用のSQLにこのカラムは含まれません。 カラムにデフォルト値を適用したい場合は、falseにすると良いでしょう。

識別子定義

識別子(主キー)であることを指定するには、 @Id を使います。

@Id
public Integer id;

複合主キーの場合は、 @Id を複数つけます。

@Id
public Integer id;

@Id
public Integer id2;

識別子は、アプリケーション側で生成することもできますが、 Seasar2に自動生成させることもできます。自動生成させるには、 @GeneratedValue を使います。

自動生成のタイプは、 @GeneratedValuestrategy 属性で指定します。指定できるタイプのは次の4つです。

GenerationType.TABLE
テーブルを使います。
GenerationType.SEQUENCE
シーケンスを使います。
GenerationType.IDENTITY
データベース固有の識別子自動生成を使います。
GenerationType.AUTO(デフォルト)
データベースに応じてTABLE・SEQUENCE・IDENTITYのどちらかが選択されます。 IDENTITYが使える場合はIDENTITYに、 IDENTITYが使えなくてSEQUENCEが使える場合はSEQUENCEに、 IDENTITYもSEQUENCEも使えない場合はTABLEになります。

GenerationType.TABLE

GenerationType.TABLEは次のようにして使います。

@Id
@GeneratedValue(strategy = GenerationType.TABLE)
public Integer id;

上記のように指定した場合、あらかじめ、次のようなテーブルとデータを用意しておく必要があります。

create table ID_GENERATOR {
  PK varchar(80) not null primary key,
  VALUE integer);
insert into ID_GENERATOR (PK, VALUE) values ('EMPLOYEE_ID', 1);

ID_GENERATORテーブルのPKカラムには、<テーブル名>_<識別子のカラム名>を設定します。

テーブル名やカラム名をカスタマイズするには、次のように@TableGeneratorアノテーションで指定します。

@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "EMPLOYEE_GEN")
@TableGenerator(
    name = "EMPLOYEE_GEN",
    table = "ID_GEN",
    pkColumnName = "GEN_NAME",
    valueColumnName = "GEN_VALUE")
public Integer id;

上記のようなTableGeneratorを定義した場合、 あらかじめ、次のようなテーブルとデータを用意しておく必要があります。

create table ID_GEN {
  GEN_NAME varchar(80) not null primary key,
  GEN_VALUE integer);
insert into ID_GEN (GEN_NAME, GEN_VALUE) values ('EMPLOYEE_GEN', 1);

GenerationType.SEQUENCE

GenerationType.SEQUENCEは次のようにして使います。

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
public Integer id;

上記のように指定した場合、あらかじめ、次のようなシーケンスを用意しておく必要があります。

create sequence EMPLOYEE_ID
  incremet by 50;

シーケンス名は、<テーブル名>_<識別子のカラム名>となります。

シーケンス名をカスタマイズするには、次のように@SequenceGeneratorアノテーションで指定します。

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "EMPLOYEE_GEN")
@SequenceGenerator(
    name = "EMPLOYEE_GEN",
    sequenceName = "EMPLOYEE_SEQ")
public Integer id;

上記のようなSequenceGeneratorを定義した場合、 あらかじめ、次のようなシーケンスを用意しておく必要があります。

create sequence EMPLOYEE_SEQ
  incremet by 50;

GenerationType.IDENTITY

GenerationType.IDENTITYは次のようにして使います。

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer id;

GenerationType.IDENTITYを使う場合、 識別子はデータベース固有の方法を使って自動生成されるようにしてください。

create table Employee {
  ID integer not null primary key generated always as identity,
  ...);

バージョン定義

バージョンチェック用であることを指定するには、 @Version を使います。更新時に、エンティティの値とカラムの値が同一かどうかをチェックし、 同一ならカラムの値がインクリメントされて更新されます。同一でない場合、 javax.persistence.OptimisticLockException が発生します。

例えば、エンティティのバージョンチェック用のプロパティの値が1だったとします。 更新時にカラムの値が1のままならOKで、2に更新されます。 カラムの値が1でない場合は、他で更新されているということなので、 javax.persistence.OptimisticLockException が発生します。

@Version
public Long version = 0L;

注意点

@Versionアノテーションは数値型のフィールドにのみ指定することができます。JPA仕様ではTimestamp型のフィールドもバージョンチェックに使用できることになっていますが、S2JDBCではサポートしていません。更新時刻の保持と排他制御は目的が違うので別のフィールドにしてください。

時制定義

java.util.Date および java.util.Calendar 型のプロパティには時制を指定します。 時制を指定するには、 @Temporal を使います。 @Temporal で指定可能な値は次のとおりです。

TemporalType.DATE
SQL標準の DATE 型 (日付のみ) として扱うことを指定します。
TemporalType.TIME
SQL標準の TIME 型 (時刻のみ) として扱うことを指定します。
TemporalType.TIMESTAMP
SQL標準の TIMESTAMP 型 (日付と時刻) として扱うことを指定します。
@Temporal(TemporalType.DATE)
public Date date;

ラージオブジェクト定義

byte[]SerializableString 型のプロパティはラージオブジェクトにすることができます。 ラージオブジェクトであることを指定するには、 @Lob を使います。

@Lob が指定されたプロパティが byte[]Serializable 型ならBLOB、 String 型ならCLOBとなります。

@Lob
public String largeName;

@Lob
public byte[] largeArray;

@Lob
public LargeDto largeDto;

永続化対象外定義

永続化対象外であることを指定するには、 @Transient を使います。 transient 修飾子も指定することもできますが、セッションリプリケーションなどの直列化の対象から外れてしまうので、 @Transient の方をお勧めします。

@Transient
public MyDto myDto;

//こちらはお勧めしない
public transient MyDto myDto2;

関連定義

多対一関連定義

多対一関連であることを指定するには、 @ManyToOne を使います。複数のEmployeeに1つのDepartementが関連付けられる場合、 EmployeeからみてDepartmentは多対一関連になります。 関連には、所有者、非所有者という概念があり、外部キーを持っているほうが所有者になります。

上記のケースは、Employeeのテーブルに、 department_id(プロパティ名はdepartmentId)という外部キーがあるので、 Employeeは関連の所有者になります。

@ManyToOne を定義するエンティティは、必ず関連の所有者になるので、外部キーに対応するプロパティが必要です。

public class Employee {
    ...
    public Integer departementId;
    
    @ManyToOne
    public Department department;
}

一対多関連定義

一対多関連であることを指定するには、 @OneToMany を使います。1つのDepartmentに複数のEmployeeが関連付けられる場合、 DepartmentからみてEmployeeは一対多関連になります。 関連には、所有者、非所有者という概念があり、外部キーを持っているほうが所有者になります。

上記のケースは、Employeeのテーブルに、 department_id(プロパティ名はdepartmentId)という外部キーがあり、 Departmentの方は、外部キーを持っていないので、 Departmentは関連の非所有者になります。

関連の非所有者の場合、必ずmappedBy属性で逆側の関連のプロパティ名を指定します。 Departmentからみて一対多でEmployeeが関連付けられていて、 そのEmployeeからみるとDepartmentがdepartmentプロパティとして、 多対一で関連付けられています。お互いが相互の関連であることを示すために mappedBy でdepartmentを指定します。

一対多の関連の型は、 List<エンティティ型> にします。 どのエンティティのリストなのかを示すためにGenericsの指定を忘れないようにしてください。

public class Department {
    ...
    @OneToMany(mappedBy = "department")
    public List<Employee> employeeList;
}

一対一関連定義

一対一関連であることを指定するには、 @OneToOne を使います。1つのEmployeeに1つのAddressが関連付けられる場合、 EmployeeからみてAddressは一対一関連になります。 同じように、1つのAddressに1つのEmployeeが関連付けられているので、 AddressからみてEmployeeも一対一関連になります。 関連には、所有者、非所有者という概念があり、外部キーを持っているほうが所有者になります。

上記のケースは、Employeeのテーブルに、 address_id(プロパティ名はaddressId)という外部キーがあるので、 Employeeは関連の所有者になります。Addressの方は、外部キーを持っていないので、 Addressは関連の非所有者になります。

関連の非所有者の場合、必ずmappedBy属性で逆側の関連のプロパティ名を指定します。 Addressから見ると一対一でEmployeeが関連付けられていて、 そのEmployeeからみるとAddressがaddressプロパティとして、 一対一で関連付けられています。お互いが相互の関連であることを示すために mappedBy でaddressを指定します。

public class Employee {
    ...
    public Integer addressId;
    
    @OneToOne
    public Address address;
}
public class Address {
    ...
    @OneToOne(mappedBy = "address")
    public Employee employee;
}

結合カラム定義

外部キーを持っている方を関連の所有者といいますが、関連の所有者側では、 @JoinColumn を使って、結合用のカラムを指定することができます。

name属性で、外部キーを指定します。 name属性を省略した場合、「関連のプロパティ名_関連テーブルの主キー」が 自動的に設定されます。 主キーは、プロパティ名ではなく、カラム名なので注意してください。

public class Employee {
    ...
    public Integer departementId;
    
    @ManyToOne
    public Department department;
}

上記の例では、 @JoinColumn が省略されているので、 name属性は、「関連のプロパティ名(department)_関連テーブルの主キー(ID)」、 つまりDEPARTMENT_IDになります。

departmentがDEPARTMENTに変換されているのは、 プロパティ名をカラム名に変換するときに、 キャメル記法は、'_'区切りになり、'_'以外は大文字に変換されるというルールがあるからです。

このルールは、convention.diconで指定されている org.seasar.framework.convention.impl.PersistenceNamingConventionImpl の fromPropertyNameToColumnName()の実装を変えることで、カスタマイズすることができます。

referencedColumnName属性で、関連テーブルの主キーを指定します。 referencedColumnName属性を省略した場合、 「関連テーブルの主キー」が自動的に設定されます。 主キーは、プロパティ名ではなく、カラム名なので注意してください。

public class Employee {
    ...
    public Integer departementId;
    
    @ManyToOne
    public Department department;
}

上記の例では、 @JoinColumn が省略されているので、 referencedColumnName属性は、「関連テーブルの主キー(ID)」、 つまりIDになります。