【问题标题】:Tree-Like Structure in Grails GORMGrails GORM 中的树状结构
【发布时间】:2013-09-30 21:04:16
【问题描述】:

我想在 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

【问题讨论】:

标签: spring hibernate grails grails-orm grails-2.0


【解决方案1】:

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

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

【讨论】:

  • 如何插入和删除节点?如何扩展与 dateCreated 等属性的关系?
  • 插入和删除,与任何其他 grails 域对象相同。在GraphNode 示例中,调用node.addToParents(parent) 或node.addToChildren(child) 以在保存前添加父级或子级。如果您想要关系本身的属性,最好将关系建模为一个单独的实体,例如GraphNode 和 GraphEdge.
  • 在mappedBy中加入告诉gorm children是通过parent映射的。
  • 这行不通,因为我的课程与您发布的课程不同。
  • 将此添加到您发布的课程中:static mappedBy = [children: 'parent'].
【解决方案2】:

泰勒是对的。要描述关系,您必须使用 2 个域类:

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

【讨论】:

  • 我认为,你需要添加'static belongsTo = [parent:TreeNode]'
猜你喜欢
  • 2011-08-18
  • 2011-01-26
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-01
  • 1970-01-01
  • 2011-12-27
相关资源
最近更新 更多