IT序号网

spring之Grails GORM中的树状结构

JeffreyZhao 2025年12月25日 编程语言 39 0

我想在Grails GORM中创建一个树状结构。该结构应作为其他对象的容器,并应完全满足以下要求:

  • 节点应具有0到n个 child 的
  • 一个节点应该恰好有一个父节点
  • 一个节点应具有0到n个同级节点

  • 如何在Grails GORM中定义这样的结构?

    我尝试了以下类(class):
    Class TreeNode { 
        String name 
        TreeNode parent 
     
        static hasMany = [children: TreeNode] 
     
        //returns the root node, and by extension, the entire tree! 
        TreeNode getRootNode(){ 
           if(parent){ 
              //if parent is not null then by definition this node is a child node of the tree. 
              return parent.getRootNode() 
           }else{ 
              //if parent is null then by definition it is the root node. 
              return this 
           } 
        } 
     
        //you might not need this function, but ill add it as it is common in tree structures 
        boolean isLeaf(){ 
           //determines if this node is a leaf node. a leaf is a node with zero childrens 
           return children.isEmpty() 
        } 
    } 
    

    但是在启动时出现以下错误:
    ERROR context.ContextLoader  - Context initialization failed 
    Message: Error creating bean with name 'pluginManager' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is org.codehaus.groovy.grails.exceptions.GrailsDomainException: Property [children] in class [class test.TreeNode] is a bidirectional one-to-many with two possible properties on the inverse side. Either name one of the properties on other side of the relationship [treeNode] or use the 'mappedBy' static to define the property that the relationship is mapped with. Example: static mappedBy = [children:'myprop'] 
        Line | Method 
    ->>  334 | innerRun  in java.util.concurrent.FutureTask$Sync 
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
    |    166 | run       in java.util.concurrent.FutureTask 
    |   1145 | runWorker in java.util.concurrent.ThreadPoolExecutor 
    |    615 | run       in java.util.concurrent.ThreadPoolExecutor$Worker 
    ^    722 | run . . . in java.lang.Thread 
    Caused by GrailsDomainException: Property [children] in class [class test.TreeNode] is a bidirectional one-to-many with two possible properties on the inverse side. Either name one of the properties on other side of the relationship [treeNode] or use the 'mappedBy' static to define the property that the relationship is mapped with. Example: static mappedBy = [children:'myprop'] 
    ->>  334 | innerRun  in java.util.concurrent.FutureTask$Sync 
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
    |    166 | run       in java.util.concurrent.FutureTask 
    |   1145 | runWorker in java.util.concurrent.ThreadPoolExecutor 
    |    615 | run       in java.util.concurrent.ThreadPoolExecutor$Worker 
    ^    722 | run . . . in java.lang.Thread 
    | Error 2013-10-04 17:36:00,730 [localhost-startStop-1] ERROR context.GrailsContextLoader  - Error initializing the application: Error creating bean with name 'pluginManager' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is org.codehaus.groovy.grails.exceptions.GrailsDomainException: Property [children] in class [class test.TreeNode] is a bidirectional one-to-many with two possible properties on the inverse side. Either name one of the properties on other side of the relationship [treeNode] or use the 'mappedBy' static to define the property that the relationship is mapped with. Example: static mappedBy = [children:'myprop'] 
    Message: Error creating bean with name 'pluginManager' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is org.codehaus.groovy.grails.exceptions.GrailsDomainException: Property [children] in class [class test.TreeNode] is a bidirectional one-to-many with two possible properties on the inverse side. Either name one of the properties on other side of the relationship [treeNode] or use the 'mappedBy' static to define the property that the relationship is mapped with. Example: static mappedBy = [children:'myprop'] 
        Line | Method 
    ->>  334 | innerRun  in java.util.concurrent.FutureTask$Sync 
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
    |    166 | run       in java.util.concurrent.FutureTask 
    |   1145 | runWorker in java.util.concurrent.ThreadPoolExecutor 
    |    615 | run       in java.util.concurrent.ThreadPoolExecutor$Worker 
    ^    722 | run . . . in java.lang.Thread 
    Caused by GrailsDomainException: Property [children] in class [class test.TreeNode] is a bidirectional one-to-many with two possible properties on the inverse side. Either name one of the properties on other side of the relationship [treeNode] or use the 'mappedBy' static to define the property that the relationship is mapped with. Example: static mappedBy = [children:'myprop'] 
    ->>  334 | innerRun  in java.util.concurrent.FutureTask$Sync 
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
    |    166 | run       in java.util.concurrent.FutureTask 
    |   1145 | runWorker in java.util.concurrent.ThreadPoolExecutor 
    |    615 | run       in java.util.concurrent.ThreadPoolExecutor$Worker 
    ^    722 | run . . . in java.lang.Thread 
    

    请您参考如下方法:

    一棵树通常每个节点只有一个父节点。您可以这样定义一个树节点,该树节点与其自身具有一对多的关系:

    class TreeNode { 
        TreeNode parent 
        static hasMany = [children: TreeNode] 
        static mappedBy = [children: 'parent'] 
    } 
    

    如果它有多个 parent ,那么从计算机科学的 Angular 来看,它实际上不是一棵树。该数据结构通常称为有向图。您可能可以将其与自身建立多对多关系,例如:
    class GraphNode { 
        static hasMany = [children: GraphNode] 
        static hasMany = [parents: GraphNode] 
        static mappedBy = [children: 'parents', parents: 'children'] 
    } 
    


    评论关闭
    IT序号网

    微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!