SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

今からでも遅くない、JPAを学ぼう!

今からでも遅くない JPAを学ぼう!(後編)
オブジェクト間の関連を理解し、JPQLを使用する

ディレクション、カーディナリティは難しくない

ダウンロード サンプルコード (14.2 KB)

Entity間の関連を実装する

 Entity間の関連を実装するには、それなりのEntityが必要になります。1から構築するのは手間がかかるため、筆者の連載「GlassFishからアプローチするJava」の第6回を参考にします。参考記事はJavaのWebアプリケーションですが、今回はSession Beanを作成するため、プロジェクトは[エンタープライズアプリケーション]を指定する必要があります。

プロジェクトの作成

 NetBeansで[ファイル]-[新規プロジェクト]をクリックすると[新規プロジェクト]画面が開きます。[カテゴリ]で「Java EE」を選択すると、[プロジェクト]のリストに[エンタープライズアプリケーション]が表示されるので選択し、[次へ]ボタンをクリックします。[新規エンタープライズアプリケーション]の[名前と場所]画面が開きます。[プロジェクト名]は任意の名前で構いません(ここでは「JPASample02」と入力します)。

 他の項目はそのままで[次へ]ボタンをクリックすると、[サーバーと設定]画面が開きます。デフォルトのままでいいと思いますが、[EJBモジュールを作成]と[Webアプリケーションモジュールを作成]のチェックボックスにチェックが入っていることを確認してください。確認後、[完了]ボタンをクリックすると3つのプロジェクトが作成されます。「JPASample02」「JPASample02-ejb」「JPASample02-war」が作成されていることを、左ペインの[プロジェクト]タブで確認してください。

アプリケーションの要件

 アプリケーションの要件は「GlassFishからアプローチするJava」の第6回とほぼ同じです。「芋焼酎酒店」という架空のネットショップを作成します。

  • 画面上部に芋焼酎のカタログを表示する
  • 銘柄の左側にあるチェックボックスにチェックを入れ、カタログの下にある[買い物かごに追加する]ボタンをクリックすると買い物かごに銘柄が追加される。本数の初期値は1とする
  • 買い物かごの本数を更新し[買い物かごを再表示する]ボタンをクリックすると、銘柄ごとの金額が計算し表示する
  • 買い物かごの下部に明細合計(銘柄の金額の合計)、送料、総合計(明細合計に送料を加えたもの)を表示する
  • [レジへ進む]ボタンをクリックすると買い物かごが空になる

 買い物かごが空の状態の「芋焼酎酒店」のイメージは図1の通りです。

図1.「芋焼酎酒店」初期状態
図1.「芋焼酎酒店」初期状態

ER図

 参考アプリケーションのER図は図2になります。

図2.当アプリケーションのER図
図2.当アプリケーションのER図

クラス図

図3.当アプリケーションのEntityオブジェクトのクラス図
図3.当アプリケーションのEntityオブジェクトのクラス図

 BasketクラスとBasketItemクラスは1対多の双方向の関連、BasketItemクラスとMeigaraクラスは多対1の単方向の関連になります。BasketクラスとBasketItemクラスはコンポジットの関係のため、Basketオブジェクトが削除される場合、BasketItemオブジェクトが存在しても意味がなくなるため、BasketItemオブジェクトを全削除する必要があります。

Entityクラスの実装

 上記のクラス図を踏まえEntityクラスを実装します。以下の3つのクラスはNetBeansの左ペインで[プロジェクト]-[JPASample02-ejb]を選択し右クリックします。[新規]-[Javaクラス]を選択すると、クラス名とパッケージ名を入力する画面が開きます。クラス名は以下の「Basket」「BasketItem」「Meigara」をおのおの作成するときに入力します。パッケージ名は何を入力しても結構ですが、ここでは「jp.kawakubo」と入力します(これは筆者の持っているドメイン名を逆さにしたものです。ドメインを持っている方はそれを使ってください)。

Basketクラスの実装

 リスト1がBASKETテーブルに対応したBasketクラスです。

リスト1.Basketクラス
001:@Entity
002:@Table(name = "BASKET")
003:public class Basket implements Serializable {
004:
005:    private int id = 0;
006:    private String userId = null;
007:    private List basketItems = null;
008:
009:    public Basket(){
010:    }
011:
012:    public Basket(int id,
013:                String userId,
014:                List basketItems) {
015:        this.id = id;
016:        this.userId = userId;
017:        this.basketItems = basketItems;
018:    }
019:
020:    @Id
021:    @GeneratedValue(strategy=GenerationType.IDENTITY)
022:    @Column(name = "ID")
023:    public int getId() {
024:        return id;
025:    }
026:
027:    public void setId(int id) {
028:        this.id = id;
029:    }
030:
031:    @Column(name = "USER_ID")
032:    public String getUserId() {
033:        return userId;
034:    }
035:
036:    public void setUserId(String userId) {
037:        this.userId = userId;
038:    }
039:
040:    @OneToMany(targetEntity = BasketItem.class,
041:        mappedBy = "basket")
042:    public List getBasketItems() {
043:        return basketItems;
044:    }
045:
046:    public void setBasketItems(List basketItems) {
047:        this.basketItems = basketItems;
048:    }
049:
050:}

 1行目のEntityアノテーションと2行目のTableアノテーションは前編と同じです。このクラスがEntityクラスであり、RDBのBASKETテーブルに対応していることを宣言しています。前編と比較して新しい箇所は、21、40、41行目です。

 BASKETテーブルのIDはAUTO_INCREMENTを指定しており、自動的に採番されています。そのようなカラムに対応するフィールド変数の場合、21行目のように、getterメソッドの前に以下を付けます。

@GeneratedValue(strategy=GenerationType.IDENTITY)

 40行目と41行目が今回のテーマである関連をどう表現するかに相当する箇所です。図2の通り、BasketクラスとBasketItemクラスはコンポジットの関連を持っています。黒いひし形がコンポジットを表しています。コンポジットとは集約よりもさらに強い結びつきを持っており、BasketItemオブジェクトはBasketオブジェクトの存在がなければ意味を持たないことを意味しています。実際に、買い物かごがなく、買い物かごの中身だけ存在していても意味はありません。40行目でBasketクラスとBasketItemクラスが1対多であることを指定しています。41行目でBasketItemクラスで宣言しているBasketのフィールド変数名(リスト2の6行目)であることを指定しています。

BasketItemクラスの実装

 リスト2がBASKET_ITEMテーブルに対応したBasketItemクラスです。

リスト2.BasketItemクラス
001:@Entity
002:@Table(name = "BASKET_ITEM")
003:public class BasketItem implements Serializable {
004:
005:    private int id = 0;
006:    private Basket basket = null;
007:    private Meigara meigara = null;
008:    private int quantity = 0;
009:
010:    public BasketItem() {
011:    }
012:    
013:    public BasketItem(int id,
014:            Basket basket,
015:            Meigara meigara,
016:            int quantity) {
017:        this.id = id;
018:        this.basket = basket;
019:        this.meigara = meigara;
020:        this.quantity = quantity;
021:    }
022:
023:    @Id
024:    @GeneratedValue(strategy=GenerationType.IDENTITY)
025:    @Column(name = "ID")
026:    public int getId() {
027:        return id;
028:    }
029:
030:    public void setId(int id) {
031:        this.id = id;
032:    }
033:
034:    @ManyToOne(targetEntity = Basket.class)
035:    @JoinColumn(name = "BASKET_ID",
036:        referencedColumnName = "ID")
037:    public Basket getBasket() {
038:        return basket;
039:    }
040:
041:    public void setBasket(Basket basket) {
042:        this.basket = basket;
043:    }
044:
045:    @ManyToOne(targetEntity = Meigara.class)
046:    @JoinColumn(name = "MEIGARA_ID",
047:        referencedColumnName = "ID")
048:    public Meigara getMeigara() {
049:        return meigara;
050:    }
051:
052:    public void setMeigara(Meigara meigara) {
053:        this.meigara = meigara;
054:    }
055:
056:    @Column(name = "QUANTITY")
057:    public int getQuantity() {
058:        return quantity;
059:    }
060:
061:    public void setQuantity(int quantity) {
062:        this.quantity = quantity;
063:    }
064:
065:}

 24行目はBasketクラスの説明と同様です。34行目から36行目がBasketItemクラスとBasketクラスの関連を表現しています。34行目でBasketItemクラスとBasketクラスが多対1であることを指定しています。35行目でBASKET_ITEMテーブルのカラム名を、36行目でBASKETテーブルのカラム名を指定します。

 45行目から47行目はMeigaraクラスとの関連を表現しています。45行目でBasketItemクラスとMeigaraクラスは多対1であることを指定しています。46行目ではBASKET_ITEMテーブルのカラム名を、47行目ではMEIGARAテーブルのカラム名を指定します。

 関連に直接関係のないフィールドは、前編同様Columnアノテーションを指定するだけです。

次のページ

この記事は参考になりましたか?

今からでも遅くない、JPAを学ぼう!連載記事一覧
この記事の著者

川久保 智晴(カワクボ トモハル)

haruプログラミング教室(https://haru-idea.jp/)主宰。COBOL、FORTRANで13年、Javaを中心としたWeb開発で11年。3つしか言語知らないのかというとそうでもなく、sed/awk、Perl、Python, PHP,  C#, JavaScriptなども一時期は業...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/5061 2010/05/14 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー