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 性能原因,我需要每条记录都直接引用其根节点。因此,“根”属性。

在我添加“root”之前,节点已正确保存。也就是说,我可以在根节点上调用 save() ,并且在所有节点中都正确分配了 parent_id 字段(根节点本身除外,其父 ID 保持为空)。

我试图在 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

Well, by always keeping a root node updated you'll find yourself constantly iterating over the tree, which is the opposite you want by keeping a reference to the root node. But if you really want to keep a root node, you could try this structure:

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
       }
    }
}

So you don't have to worry about explicitly updating your root node every single time. Just set the children nodes and you're done. Root can be found dinamically (but again, you will be iterating in the tree one way or another). Plus it's a cleaner mapping, I guess ;)

EDIT: I put another reference (to root). So you can choose if you use the getRoot method to set it dinamically or not. In any case, every node will have a reference to the root.

于 2012-08-01T04:18:31.350 回答
0

root由于引用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 回答