Red Hat Training
A Red Hat training course is available for Red Hat JBoss Web Server
2.2.3. 関連の利用
EventManager
の新しいメソッドで人物とイベントを結び付けましょう。
private void addPersonToEvent(Long personId, Long eventId) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Person aPerson = (Person) session.load(Person.class, personId); Event anEvent = (Event) session.load(Event.class, eventId); aPerson.getEvents().add(anEvent); session.getTransaction().commit(); }
Person
と Event
をロードした後、 普通のコレクションメソッドを使ってコレクションを変更します。 update()
や save()
への明示的な呼び出しはありません。 Hibernate は、 コレクションが変更されたことや更新が必要なことを自動的に検出します。 これは自動ダーティチェック と呼ばれます。 オブジェクトの名前や日付プロパティを変更すると、 このチェックを試すことができます。 「永続」ステート (特定の Hibernate の org.hibernate.Session
にバインドされている状態) である限り、 Hibernate は変更を監視し、 ライトビハインドで SQL を実行します。 通常、 作業単位の最後でのみ行われるデータベースでメモリステートを同期化するプロセスは「フラッシング」 と呼ばれます。 このコードでは、 作業単位はデータベーストランザクションのコミットまたはロールバックで終了します。
異なる作業単位で人物とイベントをロードすることもできます。 また、 永続ステートでない場合に
org.hibernate.Session
外部のオブジェクトを変更することも可能です (以前永続状態であった場合、 ステートは「分離 (detached)」と呼ばれます)。 分離されている時でもコレクションを変更することが可能です。
private void addPersonToEvent(Long personId, Long eventId) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Person aPerson = (Person) session .createQuery("select p from Person p left join fetch p.events where p.id = :pid") .setParameter("pid", personId) .uniqueResult(); // Eager fetch the collection so we can use it detached Event anEvent = (Event) session.load(Event.class, eventId); session.getTransaction().commit(); // End of first unit of work aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached // Begin second unit of work Session session2 = HibernateUtil.getSessionFactory().getCurrentSession(); session2.beginTransaction(); session2.update(aPerson); // Reattachment of aPerson session2.getTransaction().commit(); }
update
を呼び出すと、 新しい作業単位へバインドして分離オブジェクトを再び永続化します。 そのため分離状態の時に行われた変更をデータベースに保存することができます。 エンティティオブジェクトのコレクションに対して行われた変更 (追加や削除) はすべて保存の対象となります。
この例では無意味ですが、 これは独自のアプリケーションに取り入れることができる重要な概念です。 最後に
EventManager
の main メソッドへ新しいアクションを追加し、 コマンドラインから呼び出してください。 人物とイベントの識別子が必要な場合は save()
メソッドが識別子を返します (識別子を返すには以前のメソッドの一部を変更しなければならない場合があります)。
else if (args[0].equals("addpersontoevent")) { Long eventId = mgr.createAndStoreEvent("My Event", new Date()); Long personId = mgr.createAndStorePerson("Foo", "Bar"); mgr.addPersonToEvent(personId, eventId); System.out.println("Added person " + personId + " to event " + eventId); }
これは同等に重要な 2 つのクラスである 2 つのエンティティ間における関連の例です。 前述通り、
int
や java.lang.String
など、 通常 「比較的重要でない」 別のクラスや型が典型的なモデルに存在します。 これらのクラスは 「値型」 と呼ばれ、 値型のインスタンスは独自のアイデンティティを持たず、 エンティティ間で共有されません。 同じ名前の人物が 2 人存在しても、 2 人は同じ firstname
オブジェクトを参照しません。 値型は JDK のみにありませんが、 Address
クラスや MonetaryAmount
クラスなどの依存クラスを記述することが可能です。 実際に、 Hibernate のアプリケーションではすべての JDK クラスが値型として考慮されます。
値型のコレクションを設計することもできます。 これは他のエンティティへの参照のコレクションとは概念的に異なりますが、 Java ではほぼ同様に見えます。