違いは何ですか:
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
@JoinColumn(name = "companyIdRef", referencedColumnName = "companyId")
private List<Branch> branches;
...
}
そして
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY, mappedBy = "companyIdRef")
private List<Branch> branches;
...
}
@JoinColumn
は、関係の両側で使用できます。 @JoinColumn
側で@OneToMany
を使用することについての質問です(まれなケース)。そしてここで重要なのは、物理情報の重複(列名)と追加のUPDATEステートメントを生成する最適化されていないSQLクエリです。
ドキュメンテーション :によると
多対1は (ほぼ)常にJPA仕様の双方向関係の 所有者側 であるため、1対多関連は@OneToMany(mappedBy = ...)によってアノテーションが付けられます
@Entity
public class Troop {
@OneToMany(mappedBy="troop")
public Set<Soldier> getSoldiers() {
...
}
@Entity
public class Soldier {
@ManyToOne
@JoinColumn(name="troop_fk")
public Troop getTroop() {
...
}
部隊は部隊の特性を通して兵士と双方向の1対多の関係を持っています。 mappedBy側で物理マッピングを定義する必要はありません(してはいけません)。
1対多側を所有側 として双方向の1対多をマッピングするには、mappedBy要素を削除し、その多対1を挿入可能および更新可能としてfalseに更新する必要があります。この解決策は最適化されておらず、追加のUPDATEステートメントをいくつか生成します。
@Entity
public class Troop {
@OneToMany
@JoinColumn(name="troop_fk") //we need to duplicate the physical information
public Set<Soldier> getSoldiers() {
...
}
@Entity
public class Soldier {
@ManyToOne
@JoinColumn(name="troop_fk", insertable=false, updatable=false)
public Troop getTroop() {
...
}
アノテーション@JoinColumn
は、このエンティティがリレーションシップの owner であることを示します(つまり、対応するテーブルは参照先テーブルへの外部キーを持つ列を持ちます)。一方、属性mappedBy
は、このエンティティが関係の逆で、所有者は「他の」エンティティに存在します。これはまた、 "mappedBy"(完全双方向の関係)とアノテーションを付けたクラスから他のテーブルにアクセスできることを意味します。
特に、問題のコードの場合、正しい注釈は次のようになります。
@Entity
public class Company {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
private List<Branch> branches;
}
@Entity
public class Branch {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "companyId")
private Company company;
}
この記事 で説明したように、@OneToMany
アノテーションを@JoinColumn
と一緒に使用すると、単方向関連になります。
mappedBy
属性を設定して@OneToMany
を使用する場合は、双方向の関連付けがあります。つまり、mappedBy
が参照する@ManyToOne
関連付けを子側に持つ必要があります。
単方向@OneToMany
アソシエーションはあまりうまく動作しません したがって、避けるべきです。
もっと効率的な bidirectional @OneToMany
を使うほうがいいです 。
アノテーション mappedBy は理想的には常に双方向の関係の親側(Companyクラス)で使われるべきです、この場合それはChildクラス(Branchクラス)のメンバー変数 'company'を指すCompanyクラスにあるべきです)
アノテーション @JoinColumn はエンティティの関連付けに参加するためのマップされた列を指定するために使われます。このアノテーションはどのクラス(ParentまたはChild)でも使うことができますここでは両方ともそうではない子クラスではここで私はブランチクラスの外部キーを示す双方向の関係の子側(ブランチクラス)でそれを使用しました。
以下は実用的な例です。
親クラス、会社
@Entity
public class Company {
private int companyId;
private String companyName;
private List<Branch> branches;
@Id
@GeneratedValue
@Column(name="COMPANY_ID")
public int getCompanyId() {
return companyId;
}
public void setCompanyId(int companyId) {
this.companyId = companyId;
}
@Column(name="COMPANY_NAME")
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
@OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="company")
public List<Branch> getBranches() {
return branches;
}
public void setBranches(List<Branch> branches) {
this.branches = branches;
}
}
子クラス、支店
@Entity
public class Branch {
private int branchId;
private String branchName;
private Company company;
@Id
@GeneratedValue
@Column(name="BRANCH_ID")
public int getBranchId() {
return branchId;
}
public void setBranchId(int branchId) {
this.branchId = branchId;
}
@Column(name="BRANCH_NAME")
public String getBranchName() {
return branchName;
}
public void setBranchName(String branchName) {
this.branchName = branchName;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="COMPANY_ID")
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
this の答えが示すように、@JoinColumn
は必ずしも物理的な情報の場所に関連付ける必要はないことを付け加えたいと思います。親テーブルに子テーブルを指すテーブルデータがない場合でも、@JoinColumn
を@OneToMany
と組み合わせることができます。
単方向のOneToMany、逆のManyToOne、結合のない表
JPA 2.x+
でしか利用できないようです。参照全体ではなく、子クラスに親のIDのみを含めるようにしたい場合に便利です。
私はここオスカルロペスによって受け入れられた答えに同意しません。その答えは不正確です。
このエンティティがリレーションシップの所有者であることを示すのはNOT @JoinColumn
です。代わりに、これを行うのは@ManyToOne
アノテーションです(彼の例では)。
@ManyToOne
、@OneToMany
、@ManyToMany
などの関係アノテーションはJPA/Hibernateに マッピングを作成するように伝えます。 デフォルトでは、これは別々の結合テーブルを介して行われます。
@JoinColumn
@JoinColumn
の目的は、 結合列 が存在しない場合はそれを作成することです。もしそうなら、このアノテーションは name joinカラムに使うことができます。
MappedBy
MappedBy
パラメータの目的はJPAに指示することです。この関係の 反対 エンティティによってすでに関係がマップされているので、別の結合テーブルを作成しないでください。
覚えておいてください:MappedBy
は、デフォルトでは結合テーブルを作成することによって2つのエンティティを関連付けるメカニズムを生成することを目的としたリレーションシップアノテーションのプロパティです。 MappedBy
はそのプロセスを一方向に停止させます。
マッピングの仕組みは外部キーフィールドに対する3つのマッピング注釈のうちの1つを使用することによってそのクラス内で決定されるため、MappedBy
を使用しないエンティティは関係の owner と呼ばれます。これはマッピングの性質を指定するだけでなく、結合テーブルの作成も指示します。さらに、結合テーブルを抑制するオプションは、外部キーに@JoinColumnアノテーションを適用することによっても存在します。これにより、代わりに所有者エンティティのテーブル内に保持されます。
要約すると、@JoinColumn
は新しい結合列を作成するか、既存の結合列の名前を変更します。一方、MappedBy
パラメータは、結合テーブルを介して、または所有者エンティティの関連テーブルに外部キー列を作成することによってマッピングを作成するために、他の(子)クラスのリレーションシップアノテーションと共同で機能します。
MapppedBy
のしくみを説明するために、以下のコードを検討してください。 MappedBy
パラメータを削除すると、Hibernateは実際には2つの結合テーブルを作成します。どうして?多対多の関係には対称性があり、Hibernateには一方向を他の方向よりも選択する根拠がありません。
したがって、HibernateにMappedBy
を使用し、2つのエンティティ間の関係のマッピングを指示するために 他の エンティティを選択しました。
@Entity
public class Driver {
@ManyToMany(mappedBy = "drivers")
private List<Cars> cars;
}
@Entity
public class Cars {
@ManyToMany
private List<Drivers> drivers;
}
所有者クラスに@JoinColumn(name = "driverID")を追加すると(以下を参照)、結合テーブルが作成されず、代わりにCarsテーブルにdriverID外部キー列を作成してマッピングを構築します。
@Entity
public class Driver {
@ManyToMany(mappedBy = "drivers")
private List<Cars> cars;
}
@Entity
public class Cars {
@ManyToMany
@JoinColumn(name = "driverID")
private List<Drivers> drivers;
}
JPAは階層化されたAPIです。さまざまなレベルに独自の注釈があります。最高レベルは(1)永続クラスを記述するEntityレベルです。それから、(2)エンティティがリレーショナルデータベースにマッピングされると仮定する(2)リレーショナルデータベースレベル、および(3)Javaモデルがあります。
レベル1の注釈:@Entity、@ Id、@ OneToOne、@ OneToMany、@ManyToOne、@ManyToMany。これらの高レベルの注釈だけを使用して、アプリケーションに永続性を導入することができます。しかし、その場合はJPAの仮定に従ってデータベースを作成する必要があります。これらの注釈は実体/関係モデルを指定します。
レベル2アノテーション:@Table、@Column、@JoinColumn、... JPAのデフォルトに満足できない場合、または既存のデータベースにマップする必要がある場合は、エンティティ/プロパティからリレーショナルデータベースのテーブル/列へのマッピングに影響を与えます。これらのアノテーションは実装アノテーションとして見ることができ、それらはマッピングがどのように行われるべきかを指定します。
私の意見では、できるだけ高水準の注釈に固執し、次に必要に応じて低水準の注釈を導入するのが最善です。
質問に答えるには、@ OneToMany/mappedByはエンティティドメインからの注釈のみを使用するため、最も優れています。 @ oneToMany/@ JoinColumnも問題ありませんが、厳密には必要ない場合は実装アノテーションを使用します。