JavaとJavaEEプログラマのブログ

JavaEEを中心にしたをソフトウェア開発についてのブログ

JPA2.0入門 〜JPA2.0を使った、爆速RDB設計〜

事前準備

NetBeansをインストール。

http://netbeans.org/downloads/index.html?pagelang=ja からNetBeans7.2のJavaEEバンドル版をダウンロードしてインストール。
インストール時のウィザードでJUnitGlassFishもインストールする。

NetBeansでDBを作成

サービスタブをクリック。Java DBを右クリック→データベースの作成で使用するDBを作成する。

NetBeansJPA用のプロジェクトを作成

NetBeansのメニュー→ファイル→新規プロジェクト→MavenJavaアプリケーション
作成したプロジェクト内にあるpom.xml を以下のように修正。は適宜、最新に。NetBeansならCtrl+Spaceで補完される。
pom.xmlを修正したら、プロジェクトを右クリック→ビルドを実行し、必要なライブラリをダウンロードする。

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>        
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.2</version>
        </dependency>
            
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>javax.persistence</artifactId>
            <version>2.0.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.derby</groupId>
            <artifactId>derbyclient</artifactId>
            <version>10.6.2.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.derby</groupId>
            <artifactId>derby</artifactId>
            <version>10.6.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
            <version>2.3.2</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

DB接続に必要なpersistence.xmlは、最初のエンティティを作るときにウィザードで名前と場所を入力する画面で、持続性ユニットの作成チェックボックスにチェックを入れると作成用のウィザードが表示される。
persistence.xml作成のウィザードでは次を選択・入力する。

  • 持続性ライブラリはEclipseLink(JPA2.0)
  • 表生成の方針
  • データベース接続ではデータベースの新規接続を選択。新規接続ウィザードではドライバはjava DB(Network)を選択し、ホスト:localhost・ポート:1527・データベース・ユーザー名・パスワードを設定する。

RDBテーブルを設計し、Entityクラスを作成する。

設計手法は次の書籍の内容をそのまま使えばOK。最も早く確実にDBテーブルを設計できる手法が解説されている。

楽々ERDレッスン (CodeZine BOOKS)

楽々ERDレッスン (CodeZine BOOKS)


Entityクラスの作成手順は楽々ERDレッスン (CodeZine BOOKS)で解説されているように、次の通りになる。
イベントとリソースを抜きだす→イベントとリソースに項目(プロパティ)を追加していく→イベントとリソースのリレーションを設定する。

NetBEansを使ったEntityクラスの作り方

  1. 作成したプロジェクトのソース・パッケージの上で右クリック→新規→エンティティ・クラス でidプロパティだけを持つEntityクラスが生成されるので、それに必要なプロパティを追加する。

それらのプロパティを設定できるコンストラクタを追加しておくと便利。

  1. 書籍の中では各テーブルに付ける識別子の項目名を「テーブル名+ID」にしているが、JPAでは全てIDにして問題無し。
  2. リレーションの設定を行う。FK(外部キー)を設定する代わりに、対象となるEntityクラスをプロパティとして設定し、アノテーションを付加する。
  3. リファクタリング→フィールドをカプセル化 で必要なsetter・getterを作成する。
  4. ビルドを実行し、エラーが出なければ完成。サービスタブをクリックして、JavaDBの中を見てみればテーブルが作成されているのが判る。

楽々ERDレッスン (CodeZine BOOKS)のP.126から説明されている「お持ち帰りご注文用紙」をJPA2.0で設計したのが以下のコード。コンストラクタ、getter/setter は省略。

@Entity
public class Customers implements Serializable {
    
    // Customers と OrdersはOrderがCustomersを持つ一方向の一対一。
    // だからCustomer側にはリレーションの設定は不要。
    
    private String name;
    
    private String tel;
}


@Entity
public class Orders implements Serializable {
    
    // CustomersとOrdersは、OrdersがCustomersを持つ一方向の一対一。
    // このリレーションは自動解決されるので、@OneToOne は無くてもOK。
    @OneToOne
    private Customers customer;
    
    // OrdersとProductsはOrdersが複数のProductsを所有する一方向の一対多。
    @OneToMany
    private List<Products> products;
    
    @Column(length=100)
    private int orderNums;
}

@Entity
public class Products implements Serializable {
    
   // OrdersとProductsはOrdersが複数のProductsを所有する一方向の一対多。
   // 一方向なので、Productsからのリレーション設定は不要。
    
    // ProductとProductCategoryは、ProductsがProductCategoryを所有する一方向の一対一。
    private ProductCategory productCategory;
    
    //長さを指定しない場合はデフォルトでVARCHAR(200)にマッピングされる。
    private String name;
    private BigDecimal price;
    private BigDecimal TaxIncludedPrice;
}

@Entity
public class ProductCategory implements Serializable {
    // ProductsとProductCategoryは、ProductsがProductCategoryを所有する一方向の一対一。
    // 一方向なので、Productsからのリレーション設定は不要。
    
    private String name;
}


リレーションの設定に使うアノテーションは次の四つだけで充分。
どのアノテーションも一方向の関係を表すのに使え、mappedBy属性を指定できるアノテーションは双方向の関係を表すのに使う。双方向の場合はどちらか一方を、もう片方の所有者として、mappedBy属性を指定する必要がある。
@OneToOne(mappedBy)
@OneToMany(mappedBy)
@ManyToOne
@ManyToMany(mappedBy)

これらのアノテーションには登録や削除をカスケードに行うように指定するためのcascae属性も指定できる。
JPA2.0で必須のアノテーションは先に挙げたリレーションの設定用と以下のコードに存在するものだけ。
これ以外のアノテーションは既存のDBをJPAにマッピングするために存在するようなものなので、覚える必要は無い。

@Entity
//テーブル名を指定するアノテーション。
@Table(name="T_CUSTOMER")
// このエンティティに関するキャッシュを無効化。キャッシュの設定はpersistence.xmlの<shared-cache-mode>属性で設定する。
@Cashable(false)
public class Customer implements Serializable {

    // 双方向の一対多。mappedByで所有者指定する。

    // cascade属性で登録時と削除時のカスケードを指定している。
    // cascadeはEntityManager APIの呼び出しを減らせる。
    // しかし不要なテーブル結合などコストのかかるDB呼び出しを引き起こす可能性があるため、
    // 明確にカスケードが必要だと判断できる時以外は使うべきでは無い。

    // fetch属性で即時フェッチを指定している。@OneToManyのデフォルトFetchはLAZY。
        @OneToMany(mappedBy = "politician", 
            cascade={CascadeType.PERSIST, CascadeType.REMOVE}, 
            fetch= FetchType.EAGER)
    // リレーションの順序を指定している。nameで降順、noteで昇順の順序をつけるように指定している。
    @OrderBy("name DESC, note ASC")
    private List<People> peoples;

    /*BlobやCLobへのマッピング  */
    @Lob
    private byte[] image;
    
    /* 日付、時刻、タイムスタンプ型へのマッピング  */
    @Temporal(TemporalType.DATE)
    private Date since;
    
   // バージョニングに使用するプロパティ。このプロパティの更新はJPAが自動で行う。
   // LongやTimestampクラスも指定することが出来る。
   // このエンティティが同時に変更される可能性がある場合は必須。
   @Version
   private Integer version;

    /* 主キーと示すためのアノテーション。ウィザードで自動生成されるので触れる必要無し */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;