GORM / Grails的家谱模型?

时间:2013-10-22 21:27:08

标签: java spring hibernate grails grails-2.0

我在使用GORM / Grails建模家谱时遇到问题。我知道建议使用直接非循环图来模拟这样的结构。

我从Person类开始:

class Persion {
  String name 
}

可以具有以下关系:

  • 0到n个孩子
  • 0到n个兄弟姐妹(这些可能是姐妹或兄弟)
  • 0到n个伙伴(这些可能是妻子或丈夫)
  • 0到n个父母(这可能是母亲或父亲)

1。我如何建模这种关系结构?

2。如何在这些结构中插入或删除人员?

第3。如何保证结果图没有周期?

编辑:

假设我们有一个人A:

  • 儿童关系:

    • 如果将子B添加到A,则子B必须将A作为父级。
  • 家长关系:

    • 如果将父C添加​​到A,则C具有子A
  • 合作伙伴关系:

    • 如果您将合作伙伴D添加到A,则D有合作伙伴A

4 个答案:

答案 0 :(得分:3)

你可以像下面这样做。它相当于儿童,父母等。

class TreeNode  

    {


     String name





     /**
      * This method deletes a node and all the relations that are bound to this node.
      * @return
      */
     def deleteNode() {

      // delete all child relations
      def myChildren = getChildren()
      println "myChildren: "+myChildren*.name

      myChildren.each { child ->
       println "child: "+child.name
       removeFromChildren(child)
      }

      // delete all parent relations
      def myParents = getParents()
      println "myParents: "+myParents*.name
      myParents.each { parent ->
       println "parent: "+parent.name
       removeFromParents(parent)
      }


      delete(flush:true)
     }


     TreeSet<TreeNode> getChildren() {
       TreeNodeChild.executeQuery("select tnc.child from TreeNodeChild tnc where tnc.node = :node", [node: this])
     }


     TreeNode removeFromChildren(TreeNode child) {
      TreeNodeChild.findByNodeAndChild(this, child).delete(flush: true)
      this
     }

     /**
      * Add a node as type (i.e. child) to another node.
      * @param child
      * @return
      */
     TreeNode addToChildren(TreeNode child) {
      TreeNodeChild tnc = new TreeNodeChild(node: this, child: child)
      if (tnc.validate()) {

       if (!isCyclic(child, "type")) {
        println ">>>>>>>> no cycle"
        tnc.save(flush: true)
       }
       else {
        println ">>>>>>>> !!!!!!! cycle found"
       }
      }
      this
     }


     TreeSet<TreeNode> getParents() {
      TreeNodeChild.executeQuery("select tnc.node from TreeNodeChild tnc where tnc.child = :child", [child: this])
     }

     TreeNode removeFromParents(TreeNode parent) {
      TreeNodeChild.findByNodeAndChild(parent, this).delete(flush: true)
      this
     }

     TreeNode addToParents(TreeNode parent) {
      TreeNodeChild tnc = new TreeNodeChild(node: parent, child: this)
      if (tnc.validate()) {

       if (!parent.isCyclic(this, "type")) {
        println ">>>>>>>> no cycle"
        tnc.save(flush: true)
       }
       else {
        println ">>>>>>>> !!!!!!! cycle found"
       }
      }
      this
     }







     private boolean isCyclic(node) {
      boolean cyclic = false
      def myParents = this.getParents()

      // if there are parents of this node
      if (myParents.size() != 0) {

       // if the new node is in the parents set of this node
       if (myParents.contains(node)) {
        cyclic = true
        return cyclic
       }
       else {
        // go into each parent of this node and test if new node is contained in their parents
        myParents.each { parent ->
         if (cyclic) {
          return cyclic
         }
         cyclic = parent.isCyclic(node)
        }
       }
      }

      return cyclic
     }





    }

答案 1 :(得分:2)

最棘手的部分是确保没有任何递归。我能想到的最简单的建模方法是:

class Persion {
  Person mother
  Person father
  String name 

  //The methods for the other collections would be the same
  Set<Person> getChildren() {
    PersonChild.executeQuery("select pc.child from PersonChild pc where pc.person = :person", [person: this])
  }

  Person removeFromChildren(Person child) {
      PersonChild.findByPersonAndChild(this, child).delete()
      this
  }

  Person addToChildren(Person child) {
    //Something like this to prevent recursion
    //Save should fail if the person already has that person as a child

    List<Person> others = [mother, father]
    others += siblings
    others += partners

    PersonChild pc = new PersonChild(person: this, child: child)
    if (pc.validate()) {
      if (!others.contains(child)) {
        pc.save()
      }  
    }
    this
  }
}

class PersionChild {
  Person person
  Person child
}

class PersionSibling {
  Person person
  Person sibling
}

class PersonPartner {
  Person person
  Person partner
}

您可以在Spring Security插件创建的默认UserRole表之后为Person *表建模。

答案 2 :(得分:2)

我不熟悉GORM / Grails。研究表明它本质上是Java。

这是我在普通Java环境中使用的那种结构。

一个Person对象,它包含所有关系和一些简单的实用方法(例如遍历所有父项子项的getSiblings)。

关系将作为Set来管理,以减少您必须执行的参照完整性检查的数量(但不会消除它)。

将使用工厂方法创建和销毁关系。我在我的样本中使用了enum

为简洁起见,我没有实现getter和setter。您的最终解决方案应该正确使用它们。

我没有尝试过你可能需要的任何更微妙的机制 - 例如将孩子添加到特定的父母对。这是可以实现的,但在这种情况下不必要地复杂。

public class Person {
  // Using HashSet to limit possibilities of cycles - we can assume no person exists twice in each.
  private final Set<Person> parents = new HashSet<>();
  private final Set<Person> partners = new HashSet<>();
  private final Set<Person> children = new HashSet<>();
  // Person details.
  private final String name;

  // Constructor.
  public Person(String name) {
    this.name = name;
  }

  // Extract all siblings as all children of all parents.
  public Set<Person> getSiblings() {
    Set<Person> siblings = new HashSet<>();
    for (Person parent : parents) {
      siblings.addAll(parent.children);
    }
    return siblings;
  }

}

// A factory to handle family connections.
public enum Connection {
  ParentOf {
            @Override
            void connect(Person a, Person b) {
              // Connect through a's children and b's parents.
              connect(a.children, b, b.parents, a);
            }

            @Override
            void disconnect(Person a, Person b) {
              // Connect through a's children and b's parents.
              disconnect(a.children, b, b.parents, a);
            }

          },
  PartnerOf {
            @Override
            void connect(Person a, Person b) {
              // Connect through a's children and b's parents.
              connect(a.partners, b, b.partners, a);
            }

            @Override
            void disconnect(Person a, Person b) {
              // Connect through a's children and b's parents.
              disconnect(a.partners, b, b.partners, a);
            }

          },
  ChildOf {
            @Override
            void connect(Person a, Person b) {
              // The opposit of parent.
              ParentOf.connect(b, a);
            }

            @Override
            void disconnect(Person a, Person b) {
              // The opposit of parent.
              ParentOf.disconnect(b, a);
            }

          };

  abstract void disconnect(Person a, Person b);

  abstract void connect(Person a, Person b);

  /**
   * Connect b to a through aSet and a to b through bSet
   *
   * @param aSet The set in person a
   * @param b The b person
   * @param bSet The set in person b
   * @param a The a person
   */
  void connect(Set<Person> aSet, Person b, Set<Person> bSet, Person a) {
    aSet.add(b);
    bSet.add(a);
  }

  /**
   * Reverse of connect.
   *
   * @param aSet The set in person a
   * @param b The b person
   * @param bSet The set in person b
   * @param a The a person
   */
  void disconnect(Set<Person> aSet, Person b, Set<Person> bSet, Person a) {
    aSet.remove(b);
    bSet.remove(a);
  }

}

public class Tree {
  // Safe version - ensuring relationships are maintained.
  public void connect(Person a, Connection c, Person b) {
    c.connect(a, b);
  }

  public void test() {
    Person adam = new Person("Adam");
    Person eve = new Person("Eve");
    Person cain = new Person("Cain");
    Person abel = new Person("Abel");
    connect(adam, Connection.PartnerOf, eve);
    connect(adam, Connection.ParentOf, cain);
    connect(eve, Connection.ParentOf, cain);
    connect(adam, Connection.ParentOf, abel);
    connect(eve, Connection.ParentOf, abel);
  }

}

问题的最后部分:

  
      
  1. 如何保证结果图没有循环?
  2.   

实际上 - 没有多少努力 - 你做不到!我怀疑这是不可能的,但也记得在一个真正的家谱中可以有循环。用户偶然创建循环是很常见的。从不同的方式来自同一祖先也是很常见的 - 所有这一切都是表亲婚姻而且完全合法。

这不应该是您的结构的要求,它应该是您的结构的可发现功能。

答案 3 :(得分:1)

以下是我为您的问题所做的事情

域类

class Children {
String childrenName
static belongsTo = [person:Person]  
}
class Parent {
String parentName
static belongsTo = [person:Person]
}
class Partner {
String partnerName
static belongsTo = [person:Person]
}
class Person {
String personName
static hasMany = [childrens: Children,
                    parents: Parent,
                    partners: Partner,
                    siblings: Sibiling]
}
class Sibiling {
 String sibilingName
static belongsTo = [person:Person]
}

然后在控制器中我违反了标准规则在服务中执行此操作

def person = new Person();
person.personName = "Suganthan"
def children = new Children()
children.childrenName = "SuganthanchilName"
def parent = new Parent()
parent.parentName = "SuganthanParentName"
def partner = new Partner()
partner.partnerName = "SuganthanPartnerName"
def sibling = new Sibiling()
sibling.sibilingName = "SuganthanSibiligsName"

person.addToChildrens(children)
person.addToParents(parent)
person.addToPartners(partner)
person.addToSiblings(sibling)
person.save()

然后再次投入使用以获得所需的结果

def criteria = Children.createCriteria();
Children children = criteria.get {
eq('id',1 as long)
}

def criteria1 = Parent.createCriteria();
Parent parent = criteria1.get {
eq('id',1 as long)
}

def criteria2 = Partner.createCriteria();
Partner partner = criteria2.get {
eq('id',1 as long)
}

def criteria3 = Sibiling.createCriteria();
Sibiling sibiling = criteria3.get {
eq('id',1 as long)
}

    println(children.person.personName)
    println(parent.person.personName)
    println(partner.person.personName)
    println(sibiling.person.personName)

我的结果是

Suganthan

Suganthan

Suganthan

Suganthan

希望这是你所期待的并且有很多帮助