Hibernate一対多アノテーションチュートリアル

1前書き

この簡単なHibernateチュートリアルでは、JPAアノテーションを使用した1対多マッピングの例(XMLの代替)について説明します。

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

2説明

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

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

リンク:/uploads/C-1-300x110.png%20300w[]

この例では、カートシステムを実装します。カートシステムには、各カート用のテーブルと各商品用のテーブルがあります。 ** 1つのカートには many 個のアイテムを含めることができるので、ここでは1対多のマッピングがあります。

これがデータベースレベルで機能する方法は、 cart テーブルの主キーとして cart id を持ち、さらに items の外部キーとして cart idを持つことです。

そして、私たちがコードでそれを行う方法は @ OneToMany を使うことです。

データベース内の関係を反映するように Cart クラスを Items オブジェクトにマッピングしましょう。

public class Cart {

   //...

    @OneToMany(mappedBy="cart")
    private Set<Items> items;

   //...
}

@ ManyToOne を使用して Items Cart への参照を追加し、これをhttps://docs.jboss.org/hibernate/orm/4.1/manuals/en-US/html/ch07.html#collections-bidirectional[[双方向]の関係。 Bidirectional は、 carts から items に、そして items から carts にアクセスできることを意味します。

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

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

  • JDK 1.8以降

  • 休止状態 4以降

  • Maven 3以降

  • MySQL サーバー5.6以降

3セットアップ

3.1. データベース設定

以下は Cart テーブルと Items テーブルのデータベーススクリプトです。 one-to-many__マッピングには外部キー制約を使います。

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とMySQLドライバの依存関係を pom.xml ファイルに追加します。Hibernateの依存関係はJBossロギングを使用し、自動的に推移的な依存関係として追加されます。

  • Hibernateバージョン5 _。2.7。最終 _

  • MySQLドライバのバージョン 6.0.5

Hibernate およびhttps://検索の最新バージョンについては、Maven中央リポジトリーにアクセスしてください。 maven.org/classic/#search%7Cga%7C1%7Ca%3A%22mysql-connector-java%22[MySQL]依存関係。

3.3. 休止状態の設定

これがHibernateの設定です。

<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver__class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password">root</property>
        <property name="hibernate.connection.url">
          jdbc:mysql://localhost:3306/setup</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.current__session__context__class">thread</property>
        <property name="hibernate.show__sql">true</property>
    </session-factory>
</hibernate-configuration>

3.4. HibernateAnnotationUtil クラス

HibernateAnnotationUtil クラスを使用して、新しいHibernate設定ファイルを参照するだけです。

private static SessionFactory sessionFactory;

private SessionFactory buildSessionFactory() {

    Configuration configuration = new Configuration();
    configuration.configure("hibernate-annotation.cfg.xml");
    System.out.println("Hibernate Annotation Configuration loaded");

    ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
      .applySettings(configuration.getProperties()).build();
    System.out.println("Hibernate Annotation serviceRegistry created");

    SessionFactory sessionFactory
      = configuration.buildSessionFactory(serviceRegistry);

    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> items;

   //getters and setters
}

mappedBy 変数をマッピングするために使用される Items クラスでプロパティを定義するために @ OneToMany アノテーションが使用されていることに注意してください。そのため、 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 Sessionを取得し、 one-to-many アソシエーションを実装するデータベースにモデルオブジェクトを保存するための main ()メソッドを持つクラスを作成します。

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("Cart ID=" + cart.getId());
System.out.println("item1 ID=" + item1.getId()
  + ", Foreign Key Cart ID=" + item.getCart().getId());
System.out.println("item2 ID=" + item2.getId()
+ ", Foreign Key Cart ID=" + item.getCart().getId());

これは私たちのテストプログラムの出力です:

Session created
Hibernate: insert into CART values ()
Hibernate: insert into ITEMS (cart__id)
  values (?)
Hibernate: insert into ITEMS (cart__id)
  values (?)
Cart ID=7
item1 ID=11, Foreign Key Cart ID=7
item2 ID=12, Foreign Key Cart ID=7
Closing SessionFactory

6. @ ManyToOne アノテーション

セクション2で説明したように、 @ ManyToOne アノテーションを使用して 一対多 の関係を指定できます。 Many-to-one マッピングとは、このエンティティの多くのインスタンスが別のエンティティの1つのインスタンスにマッピングされることを意味します - ** art art art @

  • @ ManyToOne アノテーションを使用すると、双方向の関係も作成できます。** これについては、次のいくつかのサブセクションで詳しく説明します。

6.1. 矛盾と所有権

ここで、 Cart Items を参照していても、 Items Cart を参照していない場合、 私たちの関係は一方向になります 。オブジェクトも自然な一貫性を持ちます。

しかし、私たちの場合、関係は双方向であり、** 矛盾の可能性があります。

開発者が item1 cart に、 item2 cart2 に追加したいが、 cart2 item2 の間の参照が矛盾するように間違えている状況を想像してみてください。

Cart cart1 = new Cart();
Cart cart2 = new Cart();

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

上記のように、 item2 cart2を参照し、 cart2は item2を参照していません。

  • Hibernateは item2 をデータベースに保存するにはどうすればよいですか?

私たちは、関係の「卑劣な側」という考えを使用してこの曖昧さを解決します - 所有側に属する参照が優先され、データベースに保存されます。

6.2. 所有側としての items

2.9項のhttp://download.oracle.com/otndocs/jcp/persistence-2.0-fr-eval-oth-JSpec/[JPA仕様]に記載されているように、** many-to-oneとマークすることをお勧めします所有側としてのside

言い換えれば、 __項目 own側、 Cart はその反対側になります。

では、どうやってこれを達成したのでしょうか。

Cart クラスに mappedBy 属性を含めることで、それを反対側としてマークします。

同時に、 Items.cart フィールドに @ ManyToOne というアノテーションを付けて、 Items を所有側にしています。

「矛盾」の例に戻ると、Hibernateは** item2 の参照がより重要であり、__item2の参照をデータベースに保存することを認識しています。

結果を確認しましょう。

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

cart はスニペットで item2 を参照していますが、 item2 cart2 への参照はデータベースに保存されます。

** 6.3. 所有側としての _cart _

「1対多」の側を所有側として、「多対1」の側を逆側としてマークすることもできます。

これは推奨される方法ではありませんが、先に進んで試してみましょう。

以下のコードスニペットは、所有者側として 1対多 側の実装を示しています。

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<ItemsOIO> items;
   //..
}

mappedBy 要素を削除し、 Many-to-one @JoinColumn insertable updatable false に設定したことに注目してください。

同じコードを実行した場合、結果は逆になります。

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

上記のように、今 item2 cart. に属しています

7. 結論

JPAアノテーションを使用してHibernate ORMおよびMySQLデータベースとの1対多の関係を実装するのがいかに簡単かを説明しました。

また、双方向の関係と所有側の概念の実装方法についても学びました。

このチュートリアルのソースコードはhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-hibernate4[GitHub上で動く]にあります。