5

1対多の関係では、通常、@ ManyToOneで注釈が付けられたフィールドが所有者であり、反対側には「mappedBy」属性があります。ただし、「mappedBy」をスキップして両側に@JoinColumn(同じ列)で注釈を付けると、両側を更新できます。変更はdbにプロページされます。

1つの双方向ではなく2つの単方向の関係はありません。結合列は1つだけです。

リレーションの所有者として一方を選択しないと、どのような問題が発生する可能性がありますか?

私のエンティティは次のようになります。

@Entity
public class B {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;


   @ManyToOne
   @JoinColumn(name = "parent_id")
   @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
   private B parent;

   @OneToMany()
   @JoinColumn(name = "parent_id")
   @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
   private List<B> children = new ArrayList<B>();
...
}

パフォーマンスに影響はないようです(少なくともインサートは問題ないように見えます)。簡単なテストとログ出力を次に示します。

Session session = HibernateUtil.getSessionFactory().openSession();
    session.beginTransaction();
    B a = new B("a");
    B b = new B("b");
    B c = new B("c");
    B d = new B("d");
    B e = new B("e");
    session.save(a);
    session.save(b);
    session.save(c);
    session.save(d);
    session.save(e);
    session.getTransaction().commit();
    System.out.println("all objects saved");
    session.beginTransaction();
    a.getChildren().add(b);
    a.getChildren().add(c);
    session.save(a);
    session.getTransaction().commit();
    System.out.println("b and c added as children");
    session.beginTransaction();
    a.getChildren().add(d);
    a.getChildren().add(e);
    session.getTransaction().commit();
    System.out.println("e and f added as children");
    session.close();

Hibernate: insert into B (fieldInB, parent_id) values (?, ?)
Hibernate: insert into B (fieldInB, parent_id) values (?, ?)
Hibernate: insert into B (fieldInB, parent_id) values (?, ?)
Hibernate: insert into B (fieldInB, parent_id) values (?, ?)
Hibernate: insert into B (fieldInB, parent_id) values (?, ?)
all objects saved
Hibernate: update B set parent_id=? where id=?
Hibernate: update B set parent_id=? where id=?
b and c added as children
Hibernate: update B set parent_id=? where id=?
Hibernate: update B set parent_id=? where id=?
e and f added as children
4

4 に答える 4

3

アソシエーションの両側を適切に設定していないため、余分なSQLステートメントは表示されません。たとえば、次のように言います。

a.getChildren().add( b );

aそして、とbが関連付けられていると仮定します。しかし、b.getParent()ここに電話するとどうなりますか?このコードが「b子として追加a」し、この新しい子を返しb、発信者がナビゲートしたいとしますb.getParent()か?

むしろあなたがすべきことは次のとおりです。

a.getChildren().add( b );
b.setParent( a );

これで、慣用的なJavaコードは引き続き機能します(b.getParent()正しく動作します)。ここで、ここに複数のSQLステートメントが表示されます。これが、「所有者」として一方の側を選択する必要がある理由です。

また、完全に二段ですが、次のことを考慮してください。

a.getChildren().add( b );
b.setParent( c );

ここでデータベースに何が書き込まれますか?両側は事実上、の異なる親に名前を付けbます。では、どちらを信じますか?

于 2012-10-04T16:46:53.473 に答える
0

この記事が役立つ と思います。具体的には、以下で説明します。

単方向を双方向と等しくしない「もの」とは何ですか?単方向の関係がある場合、CustomerクラスのみがUserクラスへの参照を持ちます。Customer.getUser()によってのみユーザーを取得でき、他の方法では取得できません。Userクラスを編集するときに、Userが顧客User.getCustomer()を取得できるようにしました。

この質問はSOでも確認できます。

そして、この質問も非常に役に立ちます。

主な違いは、双方向の関係が両方向のナビゲーションアクセスを提供するため、明示的なクエリなしで反対側にアクセスできることです。また、カスケードオプションを両方向に適用することもできます。

このトピックに関するSOについては、さらに多くの質問があります。それらはあなたにとって本当に役に立ちます:)

于 2012-10-04T14:51:47.170 に答える
0

Bを保存すると問題が発生するため、これは非効率的です。

  • オブジェクトBを更新
  • オブジェクトBへのすべての子の親参照を更新します
  • 親参照を更新するオブジェクトBのすべての子にカスケードします

それ以外の

  • オブジェクトBを更新
  • 親参照を更新するオブジェクトBのすべての子にカスケードします
于 2012-10-04T15:06:59.020 に答える
0

通常、異なるエンティティタイプが(1つ/多数の)両側にありますが、この場合、単一のエンティティタイプが両側にあります。つまり、両方の側を更新していると言うとき、エンティティが1つしかないため(ここではB)、実際には片側だけを更新しています...これはそれ自体に結合されているエンティティであるため、Hibernateはそれが何によってマップされているかを認識しています。

リレーションの所有者として一方の側を選択しないことで発生する可能性のある問題については、これを自分のコードで試し(いずれかのエンティティの@OneToMany側の「mappedBy」を削除)、実行時に「 java.sql.BatchUpdateException:失敗したバッチ」。つまり、Hibernateがクラスを適切にマップできないという奇妙なSQL例外が発生します。

于 2012-10-04T15:08:26.627 に答える