1. ホーム
  2. java

[解決済み] JPA OneToMany/ManyToOne 双方向アソシエーションにおける「アソシエーションの逆側」とは何ですか?

2022-04-23 12:42:56

質問

の例の部分で @OneToMany JPAアノテーションリファレンス :

例 1-59 @OneToMany - ジェネリックを使用した顧客クラス

@Entity
public class Customer implements Serializable {
    ...
    @OneToMany(cascade=ALL, mappedBy="customer")
    public Set<Order> getOrders() { 
        return orders; 
    }
    ...
}

例 1-60 @ManyToOne - Generics を持つ Order クラス

@Entity
public class Order implements Serializable {
    ...
    @ManyToOne
    @JoinColumn(name="CUST_ID", nullable=false)
    public Customer getCustomer() { 
        return customer; 
    }
    ...
}

と思われるのですが Customer エンティティは、アソシエーションの所有者です。しかし、その説明の中で mappedBy 属性は、同じ文書の中で、次のように書かれています。

リレーションシップが双方向である場合。 にmappedBy要素を設定します。 の逆側(非所有側)にある。 フィールドの名前 またはリレーションシップを所有するプロパティ 例1-60が示すように

しかし、私の考えが間違っていなければ、この例では mappedBy は、実際には、非所有側ではなく、所有側のアソシエーションに指定されています。

そこで質問なのですが、基本的には

  1. 双方向(一対多/多対一)の関連付けでは、どちらのエンティティがオーナーになるのでしょうか?一人側を所有者として指定するにはどうすればよいですか?多者側を所有者として指定するにはどうすればよいですか?

  2. アソシエーションの逆側とはどういう意味ですか?どうすれば「一の側」を「裏の側」に指定できるのでしょうか?多面的な関連付けを行うにはどうしたらよいでしょうか?

どのように解決するのですか?

これを理解するためには、一歩下がってみる必要があります。OOでは、顧客は注文を所有しています(注文は顧客オブジェクトのリストです)。顧客なしに注文はありえません。つまり、顧客は注文の所有者であるように見えるのです。

しかし、SQLの世界では、1つの項目が実際には他の項目へのポインタを含んでいることになります。N個の注文に対して1人の顧客が存在するので、各注文にはそれが属する顧客に対する外部キーが含まれています。これがコネクションであり、オーダーがコネクション(情報)を所有する(文字通り含む)ことを意味します。これは、OO/モデルの世界とは全く逆である。

これは理解の助けになるかもしれません。

public class Customer {
     // This field doesn't exist in the database
     // It is simulated with a SQL query
     // "OO speak": Customer owns the orders
     private List<Order> orders;
}

public class Order {
     // This field actually exists in the DB
     // In a purely OO model, we could omit it
     // "DB speak": Order contains a foreign key to customer
     private Customer customer;
}

逆側は、オブジェクトのOO "owner"で、この場合はcustomerです。顧客はテーブルに注文を保存するカラムを持っていないので、注文テーブルのどこにこのデータを保存できるかを教えなければなりません(この作業は mappedBy ).

もう一つの一般的な例は、親にも子にもなりうるノードを持つツリーである。この場合、2つのフィールドは1つのクラスで使用されます。

public class Node {
    // Again, this is managed by Hibernate.
    // There is no matching column in the database.
    @OneToMany(cascade = CascadeType.ALL) // mappedBy is only necessary when there are two fields with the type "Node"
    private List<Node> children;

    // This field exists in the database.
    // For the OO model, it's not really necessary and in fact
    // some XML implementations omit it to save memory.
    // Of course, that limits your options to navigate the tree.
    @ManyToOne
    private Node parent;
}

これは、quot;外部キー" 多対一の設計が機能することを説明します。もうひとつの方法は、別のテーブルを使用してリレーションを維持するものです。つまり、最初の例では、3つのテーブルがあることになります。顧客テーブル、注文テーブル、そして主キーのペア (customerPK, orderPK) を持つ2列のテーブルです。

この方法は、上記の方法よりも柔軟性があります(1対1、多対1、1対多、多対多も簡単に扱えます)。その代償は

  • は少し遅くなります(別のテーブルを管理する必要があり、結合は2つのテーブルだけでなく3つのテーブルを使用します)。
  • 結合構文がより複雑になる(デバッグなどで多くのクエリを手作業で書かなければならない場合、面倒になることがある)
  • 接続テーブルを管理するコードに何か問題が発生した場合、突然結果が多すぎたり少なすぎたりするため、エラーが発生しやすくなります。

だから、私はこの方法をほとんど勧めないんだ。