2012-07-31 45 views
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()中通过向上走树直到找到父对象来指定'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()之后立即更新所有节点?

+0

顺便说一句,目前我正在使用Grails 1.3.7。 – 2012-07-31 22:21:21

回答

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

所以你不必担心显式更新你的根节点每一次。只需设置子节点,就完成了。根可以在dinamically找到(但是,你会一直在树中迭代)。另外它是一个更干净的映射,我猜;)

编辑:我把另一个参考(根)。所以你可以选择是否使用getRoot方法来设置它。无论如何,每个节点都会有一个对根的引用。

+0

正如问题所述,我需要root_id出现在表中。我依靠它来进行SQL性能考虑。 – 2012-08-01 14:31:40

+0

嗯。好。我会编辑。 – 2012-08-01 14:45:17

0

由于root引用this而必须发生SO,并且验证进入无限循环。尝试改变:

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

如果一个节点引用本身,而不是根 - 它意味着你有parent(错误地)未分配。

GORM以您调用save()的实例开始,并将其所有子项(即belongsTo实例)首先保存。所以,树应该保存在ultimateRoot.save()

相关问题