3

私はGrailsでこれに似たツリー構造を持っています:

class TreeNode {
  String name
  // more properties
  List children = []
  static hasMany = [children: TreeNode]
  static belongsTo = [parent: TreeNode, root: TreeNode]
  static mappedBy = [children:'parent']

  static constraints = {
    name(blank: false,maxsize: 100,)
    parent(nullable:true)
    root(nullable:false)
  }
}

SQL のパフォーマンス上の理由から、各レコードがそのルート ノードを直接参照する必要があります。したがって、「ルート」プロパティ。

「ルート」を追加する前は、ノードは正しく保存されていました。つまり、ルート ノードで save() を呼び出すことができ、parent_id フィールドがすべてのノードで適切に割り当てられました (親 ID が null のままであるルート自体を除く)。

親が見つかるまでツリーを上にたどって、 beforeInsert() で「ルート」を割り当てようとしました。

def beforeInsert = {
  def node = this
  while (node.parent) {
    node = node.parent
  }
  root = node 
}

定期的にスタック オーバーフローの例外が発生します。

at org.codehaus.groovy.grails.orm.hibernate.validation.HibernateDomainClassValidator.cascadeValidationToOne(HibernateDomainClassValidator.java:116)
    at org.codehaus.groovy.grails.validation.GrailsDomainClassValidator.cascadeToAssociativeProperty(GrailsDomainClassValidator.java:142)

スタック オーバーフロー例外が発生しない場合、各「ルート」は最終ルートではなく自身を参照します。beforeInsert() はツリーを登っていません。

この問題を分解するのを手伝ってくれませんか? GORM はツリー構造を深さ優先で保存しようとしますか? その場合、親がまだ永続化されていない場合、親 ID をどのように保存しますか? 最も重要なことは、ルート ノードで save() を呼び出してツリーを保存するにはどうすればよいかということです。そのような「ルート」は、save() の後ですべてのノードを (すぐに) 更新する必要なく適切に設定されますか?

4

2 に答える 2

1

ルート ノードを常に最新の状態に保つことで、ツリーを絶えず反復していることに気付くでしょう。しかし、本当にルート ノードを保持したい場合は、次の構造を試すことができます。

Class TreeNode {
    String name
    TreeNode parent
    TreeNode root

    static hasMany = [children: TreeNode]

    TreeNode getRoot(){
       //of course, if parent is null, it means, you're already in the root node.
       if(parent){
          return parent.getRoot()
       }else{
          return this
       }
    }
}

そのため、ルート ノードを毎回明示的に更新することを心配する必要はありません。子ノードを設定するだけで完了です。ルートは動的に見つけることができます (ただし、繰り返しますが、何らかの方法でツリーを反復することになります)。さらに、それはよりクリーンなマッピングだと思います;)

編集:別の参照を(ルートに)入れました。したがって、getRoot メソッドを使用して動的に設定するかどうかを選択できます。いずれにせよ、すべてのノードはルートへの参照を持ちます。

于 2012-08-01T04:18:31.350 に答える
0

rootを参照しているため SO が発生している必要がありthis、検証は無限ループに入ります。次のように変更してみてください:

if (!parent) {
  root = this
  return
}
def node = parent
while (node.parent) {
  node = node.parent
}
root = node

ノードがルートではなくそれ自体を参照している場合は、parent(誤って) 割り当てられていないことを意味します。

GORM は、呼び出したインスタンスから開始し、そのすべての子 (そのインスタンス) を最初save()に保存します。belongsToしたがって、ツリーは に保存する必要がありますultimateRoot.save()

于 2012-08-01T09:58:42.963 に答える