5

グレイルでは、次のようなN:1の関係を実装できます。

class Parent { hasMany = [children:Child] }
class Child  { belongsTo = [parent:Parent] }

これで(addToとremoveFromが常に適切に使用されている場合)、parent.childrenを介して親の子を取得できます。

しかし、hasManyなしでもそれを行うことができます:

class Parent { }
class Child  { belongsTo = [parent:Parent] }

次に、Child.findAllByParent(parent)を使用してすべての子を取得する必要があります。

私の質問:2番目の方法でも親の子にクエリを実行できる場合にhasManyを使用する必要がある重要な理由はありますか?

parent.childrenを参照する方が簡単な場合もあると思いますが(親と一緒に熱心に取得した場合はおそらく高速になりますか?)、一方で、子が複数ある場合、このリストはかなり長くなる可能性があります。そして、hasManyについて私が気に入らないのは、常にaddToまたはremoveFromに注意するか、親と一緒に新しい子を追加した後にセッションをクリアして、grailsがこれを自動的に行うようにする必要があることです...

子が少ない場合はhasManyを使用し、(パフォーマンス上の理由で)子が多い場合は使用しないという答えはありますか、それともその背後にもっとありますか?

4

2 に答える 2

8

hasManyとbelongsToの使用は、更新/削除が発生したときに指定するカスケード動作に関連しています。2番目の例では、カスケードは子側でALLに設定され、親側でNONEに設定されています。子を削除しても、親には何も起こりません。親を削除すると、すべての子が自動的に削除されます。

最初の例では、カスケードは親側でALLに設定され、子側でSAVE-UPDATEに設定されています。これで、次のようなことができます。

parent.addToChildren(child1)
parent.addToChildren(child2)
parent.addToChildren(child3)
parent.save(flush:true)

また、親を保存すると、すべての子が更新されます。

あなたが尋ねなかった何かに触れると、おそらく次のようなものを持つこともできます:

class Parent { hasMany = [children:Child] }
class Child  { Parent parent }

この方法で子から親への関係を定義する場合、親を削除するときに親を参照する子オブジェクトを手動で管理する必要があります*。(*これは、不正確であることが証明された以前のステートメントを修正します)

したがって、hasMany/belongsToには2つの主な考慮事項があります。

  1. 更新/削除時にどのようなカスケード戦略を実行しますか
  2. 親の子のセットを取得する必要がある場合、データにアクセスする可能性が最も高いのは、parent.getChildren()メソッドがあると非常に便利です。

アップデート:

また、明確にしておきたいのですが、hasManyを使用すると、GORMは熱心にフェッチしません。デフォルトでは、GORMは遅延フェッチ戦略を使用するため、parent.childrenにアクセスしようとするまで子を取得しません。

デフォルトで関連付けを熱心にフェッチする場合は、適切なマッピングを指定できます。

class Parent { 
  hasMany = [children:Child]
  static mapping = {
    children lazy:false
  }
}

最後に、hasMany側のaddTo/removeFromについて心配する必要があるのは気に入らないとおっしゃいました。flush:trueで保存する場合は、これを行う必要はありません。

def parent = Parent.get(id)
def child = new Child(name:'child1', parent:parent)
if(child.save(flush:true)) {
  // both sides of the relationship should be good now
} 

編集:子/親カスケードのデフォルトの逆の順序を修正し、gormがbelongsToなしで関係を処理する方法に関する誤解を修正しました

于 2010-06-29T16:40:51.487 に答える
0

素晴らしい質問です。現在受け入れられている答えは良いものです。もう1つの重要なパフォーマンスの考慮事項があります。これは、新しい子を追加して保存したときに発生することです。最初の例では、Grailsはデフォルトで、一意性を保証するために、新しい子をセットに挿入する前に、データベースから子のリスト全体をロードする必要があります。2番目のケースでは、そうではないため、パフォーマンスが大幅に向上します。http://grails.org/doc/latest/guide/single.html#sets,ListsAndMapsに従って、子を「コレクション」として定義することにより、最初の例でこの動作を回避できます。

于 2012-01-06T07:09:03.433 に答える