2.2.5.3.3. Many-to-many 多対多

<2.2.5.3.3. Many-to-many | 目次 | 2.2.5.4. Transitive persistence with cascading>

2.2.5.3.3.1. Definition

多対多関連は @ManyToMany アノテーションで定義されるよ。@JoinTable アノテーションで関連テーブルと結合条件を書かないといけないよ。関連が双方向の場合、一方が親になって、一方が反対の終端となるよ(たとえば、関連テーブルの関連する値を更新しても、無視されるよ)

@Entity
public class Employer implements Serializable {
    @ManyToMany(
        targetEntity=org.hibernate.test.metadata.manytomany.Employee.class,
        cascade={CascadeType.PERSIST, CascadeType.MERGE}
    )
    @JoinTable(
        name="EMPLOYER_EMPLOYEE",
        joinColumns=@JoinColumn(name="EMPER_ID"),
        inverseJoinColumns=@JoinColumn(name="EMPEE_ID")
    )
    public Collection getEmployees() {
        return employees;
    }
    ...
}
@Entity
public class Employee implements Serializable {
    @ManyToMany(
        cascade = {CascadeType.PERSIST, CascadeType.MERGE},
        mappedBy = "employees",
        targetEntity = Employer.class
    )
    public Collection getEmployers() {
        return employers;
    }
}

すでに多くの記述や、関連の属性の詳細を示してきたよね。@JoinTable の記述の詳細に入ろう。これは、name と、結合カラムの列(アノテーションの配列は{A,B,C}で定義するよ)、反対の結合カラムの列を定義するよ。後の二つのものは、Employee(または反対側) の主キーを参照する関連テーブルのカラムだよ。

上で見たように、もう一方では物理マッピングを定義してはいけないよ。親側のプロパティ名を引数に取る 単純な mappedBy が二つを結び付けるよ。

2.2.5.3.3.2. Default values

他のアノテーションのように、多対多関連でもほとんどの値は推測されるよ。単方向の多対多で物理マッピングが定義されないと、次のルールが適応されるよ。テーブル名は親テーブル名、_、もう一方のテーブル名を連結したものになるよ。親テーブルを参照する外部キー名は、親テーブル名、_、親テーブルの主キー名を連結したものになって、もう一方のテーブルを参照する外部キー名は、親プロパティ名、_、そのテーブルの主キー名を連結したものになるよ。単方向の一対多関連と同じルールだよ。

@Entity
public class Store {
    @ManyToMany(cascade = CascadeType.PERSIST)
    public Set<City> getImplantedIn() {
        ...
    }
}

@Entity
public class City {
    ... //no bidirectional relationship
}

結合テーブルに Store_City が使われるよ。Store_id カラムは Store テーブルへの外部キーになるよ。implantedIn_id カラムは City テーブルへの外部キーだよ。

双方向の多対多で物理マッピングがないと次のルールが適応されるよ。テーブル名は、親テーブル名、_、もう一方のテーブル名だよ。親テーブルを参照する外部キー名は、別側のプロパティ名、_、親テーブルの主キー名を連結したもので、もう一方のテーブルを参照する外部キー名は、親側のプロパティ名、_、別側の主キー名になるよ。これは、単方向の一対多関連と同じルールだよ*1

@Entity
public class Store {
    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    public Set<Customer> getCustomers() {
        ...
    }
}

@Entity
public class Customer {
    @ManyToMany(mappedBy="customers")
    public Set<Store> getStores() {
        ...
    }
}

Store_Customer が結合テーブル名になるよ。stores_id カラムは Store テーブルへの外部キーで、customers_id は Customer テーブルへの外部キーになるよ。<2.2.5.3.3. Many-to-many | 目次 | 2.2.5.4. Transitive persistence with cascading>

*1:訳注:原文では単方向とあるが、双方向の一対多では?