Hibernate1対多の注釈チュートリアル

1.はじめに

このクイックHibernateチュートリアルでは、XMLの代わりにJPAアノテーションを使用1対多のマッピングの例を紹介します。

また、双方向の関係とは何か、それらがどのように矛盾を生み出す可能性があるか、そして所有権の概念がどのように役立つかについても学びます。

2.説明

簡単に言うと、1対多のマッピングとは、テーブル内の1つの行が別のテーブル内の複数の行にマップされることを意味します。

次のエンティティ関係図を見て、1対多の関連付けを確認しましょう。

この例では、カートごとにテーブルがあり、アイテムごとに別のテーブルがあるカートシステムを実装します。1つのカートに多くのアイテムを含めることができるため、ここでは1対多のマッピングを行います。

これがデータベースレベルで機能する方法は、カートテーブルの主キーとしてcart_idを持ち、アイテムの外部キーとしてcart_idを持っていることです。

コードでそれを行う方法は、@ OneToManyを使用することです。

データベース内の関係を反映する方法で、CartクラスをItemsオブジェクトにマップしてみましょう。

public class Cart { //... @OneToMany(mappedBy="cart") private Set items; //... }

@ManyToOneを使用して、アイテムカートへの参照を追加し、これを双方向の関係にすることもできます。双方向とは、カートからアイテムにアクセスできること、およびアイテムからカートにアクセスできることを意味します

mappedByのプロパティは、我々は我々が子供のクラスの親クラスを表現するために使用している変数にHibernateを伝えるために使用するものです。

1対多の関連付けを実装するサンプルHibernateアプリケーションを開発するために、次のテクノロジーとライブラリが使用されます。

  • JDK1.8以降
  • Hibernate 5
  • Maven3以降
  • H2データベース

3.セットアップ

3.1。データベースのセットアップ

以下は、カートテーブルとアイテムテーブルのデータベーススクリプトです。1対多のマッピングには外部キー制約を使用します。

CREATE TABLE `Cart` ( `cart_id` int(11) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`cart_id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; CREATE TABLE `Items` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `cart_id` int(11) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `cart_id` (`cart_id`), CONSTRAINT `items_ibfk_1` FOREIGN KEY (`cart_id`) REFERENCES `Cart` (`cart_id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

データベースのセットアップの準備ができたので、Hibernateサンプルプロジェクトの作成に移りましょう。

3.2。Mavenの依存関係

次に、HibernateおよびH2ドライバーの依存関係をpom.xmlファイルに追加します。Hibernate依存関係はJBossロギングを使用し、推移的な依存関係として自動的に追加されます。

  • Hibernateバージョン5.2.7.Final
  • H2ドライバーバージョン1.4.197

Hibernateの最新バージョンとH2依存関係については、Maven中央リポジトリにアクセスしてください。

3.3。Hibernate構成

Hibernateの構成は次のとおりです。

  org.h2.Driver   jdbc:h2:mem:spring_hibernate_one_to_many sa org.hibernate.dialect.H2Dialect thread true  

3.4。HibernateAnnotationUtilクラス

HibernateAnnotationUtilのクラス、私たちは新しいHibernate設定ファイルを参照する必要があります。

private static SessionFactory sessionFactory; private SessionFactory buildSessionFactory() { ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder(). configure("hibernate-annotation.cfg.xml").build(); Metadata metadata = new MetadataSources(serviceRegistry).getMetadataBuilder().build(); SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build(); return sessionFactory; } public SessionFactory getSessionFactory() { if(sessionFactory == null) sessionFactory = buildSessionFactory(); return sessionFactory; }

4.モデル

マッピング関連の構成は、モデルクラスのJPAアノテーションを使用して行われます。

@Entity @Table(name="CART") public class Cart { //... @OneToMany(mappedBy="cart") private Set items; // getters and setters }

@OneToManyアノテーションは、mappedBy変数のマップに使用されるItemsクラスのプロパティを定義するために使用されることに注意してください。そのため、Itemsクラスに「cart」という名前のプロパティがあります。

@Entity @Table(name="ITEMS") public class Items { //... @ManyToOne @JoinColumn(name="cart_id", nullable=false) private Cart cart; public Items() {} // getters and setters } 

@ManyToOneアノテーションがCartクラス変数に関連付けられていることに注意することも重要です。@JoinColumnアノテーションは、マップされた列を参照します。

5.実行中

テストプログラムでは、Hibernateセッションを取得するためのmain()メソッドを使用してクラスを作成し、モデルオブジェクトをデータベースに保存して1対多の関連付け実装しています。

sessionFactory = HibernateAnnotationUtil.getSessionFactory(); session = sessionFactory.getCurrentSession(); System.out.println("Session created"); tx = session.beginTransaction(); session.save(cart); session.save(item1); session.save(item2); tx.commit(); System.out.println("Cartitem1, Foreign Key Cartitem2, Foreign Key Cartmany-to-one">6. The @ManyToOne Annotation

As we have seen in section 2, we can specify a many-to-one relationship by using the @ManyToOne annotation. A many-to-one mapping means that many instances of this entity are mapped to one instance of another entity – many items in one cart.

The @ManyToOne annotation lets us create bidirectional relationships too. We'll cover this in detail in the next few subsections.

6.1. Inconsistencies and Ownership

Now, if Cart referenced Items, but Items didn't in turn reference Cart, our relationship would be unidirectional. The objects would also have a natural consistency.

In our case though, the relationship is bidirectional, bringing in the possibility of inconsistency.

Let's imagine a situation where a developer wants to add item1 to cart and item2 to cart2, but makes a mistake so that the references between cart2 and item2 become inconsistent:

Cart cart1 = new Cart(); Cart cart2 = new Cart(); Items item1 = new Items(cart1); Items item2 = new Items(cart2); Set itemsSet = new HashSet(); itemsSet.add(item1); itemsSet.add(item2); cart1.setItems(itemsSet); // wrong!

As shown above, item2 references cart2, whereas cart2 doesn't reference item2, and that's bad.

How should Hibernate save item2 to the database? Will item2 foreign key reference cart1 or cart2?

We resolve this ambiguity using the idea of an owning side of the relationship; references belonging to the owning side take precedence and are saved to the database.

6.2. Items as the Owning Side

As stated in the JPA specification under section 2.9, it's a good practice to mark many-to-one side as the owning side.

In other words, Items would be the owning side and Cart the inverse side, which is exactly what we did earlier.

So how did we achieve this?

By including the mappedBy attribute in the Cart class, we mark it as the inverse side.

At the same time, we also annotate the Items.cart field with @ManyToOne, making Items the owning side.

Going back to our “inconsistency” example, now Hibernate knows that the item2‘s reference is more important and will save item2‘s reference to the database.

Let's check the result:

item1 ID=1, Foreign Key Cart ID=1 item2 ID=2, Foreign Key Cart ID=2

Although cart references item2 in our snippet, item2‘s reference to cart2 is saved in the database.

6.3. Cart as the Owning Side

It's also possible to mark the one-to-many side as the owning side, and many-to-one side as the inverse side.

Although this is not a recommended practice, let's go ahead and give it a try.

The code snippet below shows the implementation of one-to-many side as the owning side:

public class ItemsOIO { // ... @ManyToOne @JoinColumn(name = "cart_id", insertable = false, updatable = false) private CartOIO cart; //.. } public class CartOIO { //.. @OneToMany @JoinColumn(name = "cart_id") // we need to duplicate the physical information private Set items; //.. } 

Notice how we removed the mappedBy element and set the many-to-one @JoinColumn as insertable and updatable to false.

If we run the same code, the result will be the opposite:

item1 ID=1, Foreign Key Cart ID=1 item2 ID=2, Foreign Key Cart ID=1

As shown above, now item2 belongs to cart.

7. Conclusion

We have seen how easy it is to implement the one-to-many relationship with the Hibernate ORM and H2 database using JPA annotations.

Additionally, we learned about bidirectional relationships and how to implement the notion of an owning side.

The source code in this article can be found over on GitHub.