171

@OneToManyJPAアノテーションリファレンスのサンプルセクション:

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

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

例1-60@ManyToOne-ジェネリックスを使用したクラスの注文

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

Customer実体は協会の所有者であるように私には思えます。ただし、mappedBy同じドキュメントの属性の説明では、次のように記述されています。

関係が双方向の場合は、例1-60に示すように、関連付けの逆(非所有)側にあるmappedBy要素を、関係を所有するフィールドまたはプロパティの名前に設定します。

しかし、私が間違っていなければ、例のように、mappedBy実際には、非所有側ではなく、関連付けの所有側で指定されています。

だから私の質問は基本的に:

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

  2. 「関連付けの逆側」とはどういう意味ですか?片側を逆としてどのように指定できますか?多辺を逆としてどのように指定できますか?

4

6 に答える 6

318

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

しかし、SQLの世界では、一方の項目には実際にはもう一方の項目へのポインターが含まれます。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「所有者」(この場合は顧客)です。顧客には注文を保存するための列がテーブルにないため、注文テーブルのどこにこのデータを保存できるかを顧客に伝える必要があります(これはを介して行われますmappedBy)。

もう1つの一般的な例は、親と子の両方になることができるノードを持つツリーです。この場合、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;
}

これは、「外部キー」の多対1の設計作業について説明しています。関係を維持するために別のテーブルを使用する2番目のアプローチがあります。つまり、最初の例では、3つのテーブルがあります。1つは顧客、1つは注文、2列のテーブルには主キーのペア(customerPK、orderPK)があります。

このアプローチは、上記のアプローチよりも柔軟性があります(1対1、多対1、1対多、さらには多対多を簡単に処理できます)。価格はそれです

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

そのため、このアプローチをお勧めすることはめったにありません。

于 2010-04-06T12:00:41.333 に答える
37

データベースに外部キーを持つテーブルを持つエンティティは所有エンティティであり、指されている他のテーブルは逆エンティティです。

于 2011-10-21T10:40:16.077 に答える
15

双方向関係の単純なルール:

1. 多対 1 の双方向関係では、常に多側が関係の所有側になります。例: 1 つの部屋には多くの人がいます (人は 1 つの部屋のみに属します) -> 所有側は人です

2.1 対 1 の双方向関係の場合、所有側は、対応する外部キーを含む側に対応します。

3. 多対多の双方向関係の場合、いずれかの側が所有側になる場合があります。

希望はあなたを助けることができます。

于 2014-02-24T17:37:47.010 に答える
4

Customer と Order の 2 つのエンティティ クラスに対して、hibernate は 2 つのテーブルを作成します。

考えられるケース:

  1. mappingBy は Customer.java および Order.java クラスでは使用されません。

    顧客側で、CUSTOMER_ID と ORDER_ID のマッピングを保持する新しいテーブル [name = CUSTOMER_ORDER] が作成されます。これらは、Customer テーブルと Order テーブルの主キーです。注文側では、対応する Customer_ID レコード マッピングを保存するために追加の列が必要です。

  2. MappedBy は Customer.java で使用されています [問題文に記載されているとおり] 追加のテーブル [CUSTOMER_ORDER] は作成されません。注文テーブルの列は 1 つだけ

  3. Mappedby は Order.java で使用され、hibernate によって追加のテーブルが作成されます。[name = CUSTOMER_ORDER] 注文テーブルには、マッピング用の追加の列 [Customer_ID] がありません。

どのサイドも関係の所有者にすることができます。ただし、xxxToOne 側を選択することをお勧めします。

コーディング効果 - > エンティティの所有側のみが関係ステータスを変更できます。以下の例では、BoyFriend クラスが関係の所有者です。彼女は別れたくても別れられない。

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "BoyFriend21")
public class BoyFriend21 {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Boy_ID")
    @SequenceGenerator(name = "Boy_ID", sequenceName = "Boy_ID_SEQUENCER", initialValue = 10,allocationSize = 1)
    private Integer id;

    @Column(name = "BOY_NAME")
    private String name;

    @OneToOne(cascade = { CascadeType.ALL })
    private GirlFriend21 girlFriend;

    public BoyFriend21(String name) {
        this.name = name;
    }

    public BoyFriend21() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BoyFriend21(String name, GirlFriend21 girlFriend) {
        this.name = name;
        this.girlFriend = girlFriend;
    }

    public GirlFriend21 getGirlFriend() {
        return girlFriend;
    }

    public void setGirlFriend(GirlFriend21 girlFriend) {
        this.girlFriend = girlFriend;
    }
}

import org.hibernate.annotations.*;
import javax.persistence.*;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.ArrayList;
import java.util.List;

@Entity 
@Table(name = "GirlFriend21")
public class GirlFriend21 {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Girl_ID")
    @SequenceGenerator(name = "Girl_ID", sequenceName = "Girl_ID_SEQUENCER", initialValue = 10,allocationSize = 1)
    private Integer id;

    @Column(name = "GIRL_NAME")
    private String name;

    @OneToOne(cascade = {CascadeType.ALL},mappedBy = "girlFriend")
    private BoyFriend21 boyFriends = new BoyFriend21();

    public GirlFriend21() {
    }

    public GirlFriend21(String name) {
        this.name = name;
    }


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public GirlFriend21(String name, BoyFriend21 boyFriends) {
        this.name = name;
        this.boyFriends = boyFriends;
    }

    public BoyFriend21 getBoyFriends() {
        return boyFriends;
    }

    public void setBoyFriends(BoyFriend21 boyFriends) {
        this.boyFriends = boyFriends;
    }
}


import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import java.util.Arrays;

public class Main578_DS {

    public static void main(String[] args) {
        final Configuration configuration = new Configuration();
         try {
             configuration.configure("hibernate.cfg.xml");
         } catch (HibernateException e) {
             throw new RuntimeException(e);
         }
        final SessionFactory sessionFactory = configuration.buildSessionFactory();
        final Session session = sessionFactory.openSession();
        session.beginTransaction();

        final BoyFriend21 clinton = new BoyFriend21("Bill Clinton");
        final GirlFriend21 monica = new GirlFriend21("monica lewinsky");

        clinton.setGirlFriend(monica);
        session.save(clinton);

        session.getTransaction().commit();
        session.close();
    }
}

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import java.util.List;

public class Main578_Modify {

    public static void main(String[] args) {
        final Configuration configuration = new Configuration();
        try {
            configuration.configure("hibernate.cfg.xml");
        } catch (HibernateException e) {
            throw new RuntimeException(e);
        }
        final SessionFactory sessionFactory = configuration.buildSessionFactory();
        final Session session1 = sessionFactory.openSession();
        session1.beginTransaction();

        GirlFriend21 monica = (GirlFriend21)session1.load(GirlFriend21.class,10);  // Monica lewinsky record has id  10.
        BoyFriend21 boyfriend = monica.getBoyFriends();
        System.out.println(boyfriend.getName()); // It will print  Clinton Name
        monica.setBoyFriends(null); // It will not impact relationship

        session1.getTransaction().commit();
        session1.close();

        final Session session2 = sessionFactory.openSession();
        session2.beginTransaction();

        BoyFriend21 clinton = (BoyFriend21)session2.load(BoyFriend21.class,10);  // Bill clinton record

        GirlFriend21 girlfriend = clinton.getGirlFriend();
        System.out.println(girlfriend.getName()); // It will print Monica name.
        //But if Clinton[Who owns the relationship as per "mappedby" rule can break this]
        clinton.setGirlFriend(null);
        // Now if Monica tries to check BoyFriend Details, she will find Clinton is no more her boyFriend
        session2.getTransaction().commit();
        session2.close();

        final Session session3 = sessionFactory.openSession();
        session1.beginTransaction();

        monica = (GirlFriend21)session3.load(GirlFriend21.class,10);  // Monica lewinsky record has id  10.
        boyfriend = monica.getBoyFriends();

        System.out.println(boyfriend.getName()); // Does not print Clinton Name

        session3.getTransaction().commit();
        session3.close();
    }
}
于 2013-08-10T17:05:46.233 に答える