如何一步保存“rooted”域类树?

时间:2012-07-31 21:45:46

标签: grails gorm

我在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'属性。

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

我试图通过向上走树直到找到父对象来在beforeInsert()中指定'root'。

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)

当没有发生堆栈溢出异常时,每个“root”引用自身而不是最终根。 beforeInsert()不会爬树。

你能帮我解决这个问题吗? GORM是否尝试先深度保存我的树结构?如果是这样,如果父级尚未保留,它如何保存父ID?最重要的是,如何通过在根节点上调用save()来保存树,这样“root”是否正确设置而不必在save()之后立即更新所有节点?

2 个答案:

答案 0 :(得分: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
       }
    }
}

因此,您不必担心每次都明确更新根节点。只需设置子节点即可完成。 Root可以在dinamically中找到(但同样,你将以某种方式在树中迭代)。另外,我认为这是一个更清晰的映射;)

编辑:我把另一个引用(到root)。因此,您可以选择是否使用getRoot方法将其设置为dinamically。在任何情况下,每个节点都将具有对根的引用。

答案 1 :(得分: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()

相关问题