Grails GORM中的树状结构

时间:2013-09-30 21:04:17

标签: spring hibernate grails gorm grails-2.0

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

  • 一个节点应该有0到n个孩子
  • 一个节点应该只有一个父节点
  • 一个节点应该有0到n个兄弟节点

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

我尝试了以下课程:

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

2 个答案:

答案 0 :(得分:2)

树通常每个节点有一个父节点。您可以定义一个与自身具有一对多关系的树节点,如下所示:

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

如果它有多个父母,那么它实际上并不是计算机科学意义上的树。该数据结构通常称为有向图。您可以将其建模为与自身的多对多关系,如下所示:

class GraphNode {
    static hasMany = [children: GraphNode]
    static hasMany = [parents: GraphNode]
    static mappedBy = [children: 'parents', parents: 'children']
}

答案 1 :(得分:0)

ataylor是对的。要描述关系,你必须使用2个Domain类:

class Node {
    static hasMany = [relations: Relation]
}
class Relation {
    Node fromNode
    Node toNode
    String name //ex. 'son'
    String reverseName // ex. 'father'
}