【问题标题】:Tree structure in GORM (grails)GORM 中的树结构(grails)
【发布时间】:2011-08-18 08:23:55
【问题描述】:

我正在尝试在 GORM 中定义树结构。这是我的模型:

class Tree {
    String name
    Level rootLevel

    static hasOne = [rootLevel: Level]
    static hasMany = [levels: Level]
    static mappedBy = [levels:"parentTree"]
}

class Level {
    String name
    Tree parentTree
    Level parentLevel
    Set<Level> subLevels

    static belongsTo = [parentTree: Tree]
    static hasMany = [subLevels: Level]
}

插入似乎工作正常,但是当我无法加载具有许多级别和子级别的树时。 我想我在关系中遗漏了一些东西: - 树应该有对 rootLevel 的引用(并且可以选择所有子级别) - 关卡应该有对其父关卡、子关卡和全局父树的引用

你能指出正确的方向来获得这样的树结构吗? 谢谢

【问题讨论】:

  • Hibernate 不喜欢递归结构,但这是可能的。请解释您的意思是“但是当我无法加载具有许多级别和子级别的树时”。你得到一个错误还是什么?
  • 问题是关卡是用父树ID填充的,但是当你加载树时,你有以下错误“多行与给定的标识符被发现”级别类。

标签: java hibernate grails groovy grails-orm


【解决方案1】:

我不喜欢你的树形结构,所以我创建了自己的:)

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

至于确保加载所有树节点,您始终可以对每个树节点使用急切/非延迟获取,包括父节点和子节点。但是,如果您的树结构非常大,可能会降低性能...

至于急切/懒惰的获取。看这里:Using lazy property fetching in Grails / Gorm

【讨论】:

  • 感谢您的回复。事实上,使用这种方法,您可以避免树、级别和子级别之间的关系混乱。但是正如你所说,没有直接引用父树,这对我来说不是最好的场景。
  • 有一个对父树的直接引用,但不是根树,如果那是你的ment的话。但是,可以从每个 TreeNode 实例中获取根树。或者,您始终可以通过将TreeNode rootNode 添加到类定义来添加对根节点的显式引用。为什么我的原始方案不适合您?
  • 另一种解决方法是设置TreeNode getRootNode(){ String hql = "From TreeNode where parent is null" return TreeNode.execureQuery(hql) }
  • 如您所说,检索根 TreeNode 的递归方式会带来性能损失。但是使用最后一个选项,这绝对可行。
  • 在这种情况下,我们是否应该添加静态 mappedBy 来命名属性以指定哪个集合 mappedBy 作为父集合? Class TreeNode{ ....static mappedBy = [children:'parent'] .... } 还是我错了?
【解决方案2】:

问题是关卡是用父树 ID 填充的,但是当您加载树时,您会遇到关卡类的以下错误“找到具有给定标识符的多行”。

您的问题似乎是每棵树都有多个根节点。这是一种不寻常的方法。要使其工作,您必须将实体Tree 中的Level rootLevel 替换为Set&lt;Level&gt; roots

【讨论】:

  • 这就是我同时拥有 hasOne 和 hasMany 的原因。它具有完全链接结构的目的:从 Tree 访问 rootLevel 和所有可能的子级别,从 Level 访问 parentLevel 以及从任何级别访问 Tree。
  • Hibernate 错误意味着“实体树有多个 LEVEL 类型的子级,但 Java 类中的字段只是一个引用”。因此,您必须在同一棵树中添加了多个根节点。
【解决方案3】:

我最终得到了这个解决方案(感谢朋友):

class Tree {
   String name
   Level rootLevel

   static hasMany = [levels: Level]
   static mappedBy = [rootLevel: "parentTree", levels: "owningTree"]

   static constraints = {rootLevel(nullable: true)}
}

class Level {
   String name
   Tree parentTree
   Tree owningTree
   Level parentLevel
   Set<Level> subLevels

   static belongsTo = [owningTree: Tree, parentLevel: Level]
   static hasMany = [subLevels: Level]
   static mappedBy = [parentTree: "rootLevel", owningTree: "levels", subLevels: "parentLevel"]

   static constraints = {
       parentTree(nullable: true)
       parentLevel(nullable: true)
   }
}

我错过了 Tree 和 Level(owningTree 和 parentTree)之间的两个关系以及一些 mappedBy 配置来帮助休眠。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    • 2013-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多