誰かがJPAとHibernateでmappedByを説明できますか?


174

私は休止状態に慣れていないため、1対多および多対1の関係を使用する必要があります。私のオブジェクトでは双方向の関係なので、どちらの方向からでもトラバースできます。mappedBy推奨される方法ですが、理解できませんでした。誰かが説明できますか:

  • それを使用するための推奨される方法は何ですか?
  • それはどんな目的を解決しますか?

私の例のために、ここに注釈付きのクラスがあります:

  • Airline 多くの AirlineFlights
  • 多く AirlineFlightsONEに属しています Airline

航空会社

@Entity 
@Table(name="Airline")
public class Airline {
    private Integer idAirline;
    private String name;

    private String code;

    private String aliasName;
    private Set<AirlineFlight> airlineFlights = new HashSet<AirlineFlight>(0);

    public Airline(){}

    public Airline(String name, String code, String aliasName, Set<AirlineFlight> flights) {
        setName(name);
        setCode(code);
        setAliasName(aliasName);
        setAirlineFlights(flights);
    }

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="IDAIRLINE", nullable=false)
    public Integer getIdAirline() {
        return idAirline;
    }

    private void setIdAirline(Integer idAirline) {
        this.idAirline = idAirline;
    }

    @Column(name="NAME", nullable=false)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = DAOUtil.convertToDBString(name);
    }

    @Column(name="CODE", nullable=false, length=3)
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = DAOUtil.convertToDBString(code);
    }

    @Column(name="ALIAS", nullable=true)
    public String getAliasName() {
        return aliasName;
    }
    public void setAliasName(String aliasName) {
        if(aliasName != null)
            this.aliasName = DAOUtil.convertToDBString(aliasName);
    }

    @OneToMany(fetch=FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinColumn(name="IDAIRLINE")
    public Set<AirlineFlight> getAirlineFlights() {
        return airlineFlights;
    }

    public void setAirlineFlights(Set<AirlineFlight> flights) {
        this.airlineFlights = flights;
    }
}

AirlineFlights:

@Entity
@Table(name="AirlineFlight")
public class AirlineFlight {
    private Integer idAirlineFlight;
    private Airline airline;
    private String flightNumber;

    public AirlineFlight(){}

    public AirlineFlight(Airline airline, String flightNumber) {
        setAirline(airline);
        setFlightNumber(flightNumber);
    }

    @Id
    @GeneratedValue(generator="identity")
    @GenericGenerator(name="identity", strategy="identity")
    @Column(name="IDAIRLINEFLIGHT", nullable=false)
    public Integer getIdAirlineFlight() {
        return idAirlineFlight;
    }
    private void setIdAirlineFlight(Integer idAirlineFlight) {
        this.idAirlineFlight = idAirlineFlight;
    }

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="IDAIRLINE", nullable=false)
    public Airline getAirline() {
        return airline;
    }
    public void setAirline(Airline airline) {
        this.airline = airline;
    }

    @Column(name="FLIGHTNUMBER", nullable=false)
    public String getFlightNumber() {
        return flightNumber;
    }
    public void setFlightNumber(String flightNumber) {
        this.flightNumber = DAOUtil.convertToDBString(flightNumber);
    }
}

編集:

データベーススキーマ:

AirlineFlightsにはidAirlineがForeignKeyとしてあり、AirlineにはidAirlineFlightsがありません。これにより、AirlineFlightsが所有者/識別エンティティになりますか?

理論的には、airlineFlightsの所有者になりたいです。

ここに画像の説明を入力してください

回答:


150

@JoinColumn両方のモデルでを指定すると、双方向の関係はなくなります。片方向の関係が2つあり、非常に混乱しているマッピングです。両方のモデルがIDAIRLINE列を「所有」していることを伝えています。実際にはそのうちの1つだけが実際にすべきです!「通常の」ことは@JoinColumn@OneToMany完全にサイドを外して、代わりにmappedByをに追加すること@OneToManyです。

@OneToMany(cascade = CascadeType.ALL, mappedBy="airline")
public Set<AirlineFlight> getAirlineFlights() {
    return airlineFlights;
}

これは、Hibernateに「設定を見つけるために私がコレクションを持っているものの 'airline'という名前のBeanプロパティを調べてください」と伝えます。


1
最終的に、mappedByについての説明に少し混乱しています。dbでどのように構成されているかは重要ですか?@DB:AirlineFlightsは、外部キーとしてidAirlineを持っています。航空会社は主キーとしてidAirlineのみを持ち、AirlineFlights @ DBに関する情報を保持しません。
ブレイニーデクスター

10
はい、それは重要です。mappedByの名前は、JoinColumnの構成の場所をHibernateに伝えています。(AirlineFlightのgetAirline()メソッドでは。)の方法、あなたは、あなたがそれをすることを言っている航空会社の航空会社にJoinColumnを入れて、それをマッピングしている他の表の上の値を維持する責任を。エンティティに、別のテーブルの列を「所有」していることを通知し、それを更新する責任があります。これは通常行うことではなく、SQLステートメントの実行順序に問題を引き起こす可能性があります。
2012

編集をご覧ください。DBレベルでは、airlineFlightテーブルはidAirlineを外部キー列として所有します。したがって、JoinColumnはその列を所有しているため、対応するManytoOneのairlineFlightクラス/テーブルに配置する必要があります。
ブレイニーデクスター

はい、そのようにすることをお勧めします。これは最も複雑なオプションではなく、他に何も必要ないようです。
2012

「@OneToManyサイドから@JoinColumnを完全に取り除く」という意味@ManyToOneですか?
nbro 2016

284

MappedByは、関係のキーが反対側にあることを休止状態に通知します。

つまり、2つのテーブルをリンクしても、それらのテーブルのうち1つだけが他のテーブルに対して外部キー制約を持っています。MappedByを使用すると、制約を含まないテーブルから他のテーブルにリンクできます。


3
もう少し詳しく説明してもらえますか?
Alexander Suraphel 2013年

1
@Kurt Du Bois、mappedBy双方向を定義するのではなく、なぜ使用するのですか(両側にforeign_key制約があります)?
Kevin Meredith 14年

6
時々、両側に鍵を置くことは意味をなさないからです。たとえば、会社とポータブルがあるとします。ポータブルは1つの会社にのみ属しますが、会社には複数のポータブルがあります。
カートデュボワ2014年

私の答えをロールバックして編集者に申し訳ありませんが、編集には実際にはまったく付加価値がありませんでした。最後の文は意味がありませんでした。
カートデュボワ

@KurtDuBoisのようにマップされるのは、データベースをどのように作成するかを画像に含めるだけです。つまり、Java側でmapbyを使用するか、休止状態にしないかは、同様に動作します。

22

mappedbyそれ自体が語るので、このフィールドをマップしないように休止状態に指示します。このフィールド[name = "field"]によってすでにマップされています。
フィールドは他のエンティティにあり(name of the variable in the class not the table in the database)ます。

これを行わないと、Hibernateはこの2つの関係をマッピングします。同じ関係ではないためです。

そのため、hibernateに片側のみでマッピングを行い、それらの間で調整するように指示する必要があります。


ismapByはオプションですか?mappedByを使用せずに同じ結果、つまり双方向オブジェクトマッピングを取得しているため
Freelancer

many2manyの一方の側で同じようにmappedByを使用せずにon2manyとmany2oneを使用することはできません。一方の側でmappedByを使用する必要があります
Charif DZ

属性値が何を意味するかを指摘していただきありがとうございます。これは、他のテーブルのフィールドの名前です。
Gab是好人

2
おそらく休止状態は必ずしもそれ自身で話すとは限らないかもしれませんが、その場合、少なくとも句読点を使用します
Amalgovinus

1
私にとっては、それはそれ自体のために語っていません。逆に、それは非常に混乱しています。ただ、実際に何であるかに関する質問の量を見てmappedByinversedBy。他のORMは、はるかに知的な使用belongsToManyhasMany属性。
Jan Bodnar

12

mappedby = "別のクラスで作成された同じクラスのエンティティのオブジェクト"

注:-Mapped byは、1つのテーブルに外部キー制約を含める必要があるため、1つのクラスでのみ使用できます。マッピングされたが両方に適用できる場合は、両方のテーブルから外部キーを削除します。外部キーがないと、2つのテーブルの間に関係はありません。

注:-次のアノテーションに使用できます:-1. @ OneTone 2. @ OneToMany 3. @ ManyToMany

注---次のアノテーションには使用できません:-1. @ ManyToOne

1対1で:-マッピングの任意の側で実行しますが、片側でのみ実行します。それはそれが適用されるクラスのテーブルの外部キー制約の余分な列を削除します。

たとえば。マップされたをEmployeeクラスのemployeeオブジェクトに適用すると、Employeeテーブルの外部キーが削除されます。


12

テーブルの関係とエンティティの関係

リレーショナルデータベースシステムでは、one-to-manyテーブルの関係は次のようになります。

<code> 1対多</ code>テーブルの関係

関係はpost_id、子テーブルの外部キー列(たとえば、)に基づいていることに注意してください。

したがって、one-to-manyテーブルのリレーションシップを管理することに関しては、単一の真の情報源があります。

ここで、one-to-many前に見たテーブルの関係にマップする双方向エンティティの関係を取得すると、次のようになります。

双方向の<code> One-To-Many </ code>エンティティの関連付け

上の図を見ると、この関係を管理する方法が2つあることがわかります。

ではPostエンティティ、あなたが持っているcommentsコレクションを:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();

また、PostCommentでは、post関連付けは次のようにマッピングされます。

@ManyToOne(
    fetch = FetchType.LAZY
)
@JoinColumn(name = "post_id")
private Post post;

外部キー列を表す方法は2つあるため、関連付けの状態の変化を対応する外部キー列の値の変更に変換する場合、どちらが真のソースであるかを定義する必要があります。

MappedBy

このmappedBy属性は、@ManyToOne側面が外部キー列の管理を担当することを示し、コレクションは子エンティティをフェッチし、親エンティティの状態変更を子にカスケードするためにのみ使用されます(たとえば、親を削除すると子エンティティも削除されます)。

双方向の関連付けの両側を同期する

これで、mappedBy属性を定義し、子側の@ManyToOne関連付けが外部キー列を管理する場合でも、双方向の関連付けの両側を同期する必要があります。

これを行う最良の方法は、次の2つのユーティリティメソッドを追加することです。

public void addComment(PostComment comment) {
    comments.add(comment);
    comment.setPost(this);
}

public void removeComment(PostComment comment) {
    comments.remove(comment);
    comment.setPost(null);
}

addComment及びremoveComment方法は、両側が同期されていることを確認します。したがって、子エンティティを追加する場合、子エンティティは親を指す必要があり、親エンティティは子を子コレクションに含める必要があります。

すべての双方向エンティティ関連タイプを同期する最良の方法の詳細については、こちらの記事をご覧ください。


0

ManyToOneマッピングから始めて、次に、BiDirectionalの方法にOneToManyマッピングも配置しました。次に、OneToMany側(通常は親のテーブル/クラス)で「mappedBy」(マッピングは子のテーブル/クラスによって行われる)に言及する必要があるため、HibernateはDBにEXTRAマッピングテーブルを作成しません(TableName = parent_childなど)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.