Дерево меню с Hibernate в игре! - PullRequest
       4

Дерево меню с Hibernate в игре!

2 голосов
/ 21 февраля 2011

Мой первый проект с Hibernate / JPA и Play !, у меня есть меню, которое когда-то будет работать, будет поддерживать изменения (то есть легко добавлять узлы в дерево).Изо всех сил (в смысле> 5 часов), чтобы собрать вместе базовое моделирование:

Модель:

@Entity
@Table(name = "Node")
public class Node extends Model {

    @Column(nullable=false)
    public String description;

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="parent")
    public List<Node> children = new LinkedList<Node>();

    @ManyToOne
    @JoinColumn(name="parent", insertable=false, updatable=false)
    public Node parent;

    public Node(){}

}

Класс утилит:

public class NodeUtil {

    public static void addChild(Node root, String description) {

        Node child = new Node();
        child.description = description;
        child.parent = root;

        root.children.add(child);

        root.save();

    }

    private static final String MENU_NAME = "MainMenu";

    public static Node getMenu() {
        return getRoot(MENU_NAME);
    }
    public static Node getRoot(String name) {
        Node root = Node.find("byDescription", name).first();
        if (root == null) {
            root = new Node();
            root.description = name;
            root.save();
        }

        return root;
    }

}

Тест:

public class MenuTest extends UnitTest {

    private static final String TEST_MENU = "testMenu";

    @Test
    public void testMenu() {

        // test build/get

        Node root = NodeUtil.getRoot(TEST_MENU);
        assertNotNull(root);

        // delete all children - maybe from previous tests etc.
        for(Node o : root.children)
           o.delete();
        root.save();

        // test add

        root = NodeUtil.getRoot(TEST_MENU);

        NodeUtil.addChild(root, "child 1");
        NodeUtil.addChild(root, "child 2");
        NodeUtil.addChild(root, "child 3");

        assertEquals(3, root.children.size());
        assertEquals("child 3", root.children.get(2).description);

        assertEquals(0, root.children.get(1).children.size());

        Node node = root.children.get(1);
        NodeUtil.addChild(node, "subchild 1");
        NodeUtil.addChild(node, "subchild 2");
        NodeUtil.addChild(node, "subchild 3");
        NodeUtil.addChild(node, "subchild 4");

        NodeUtil.addChild(root.children.get(2), "sub subchild");

        assertEquals("sub subchild", root
                                    .children.get(1)
                                    .children.get(2)
                                    .children.get(0)
                                    .description);

        assertEquals(4, root.children.get(1).children.size());

        root.save();

        // test delete

        root = NodeUtil.getRoot(TEST_MENU); // regrab the root via hibernate, assuming there isnt it isnt cached this will get changes that have been persisted to the db (maybe?)

        root.children.get(1).children.get(2).delete();
        assertEquals(3, root.children.get(1).children.size());

        //root.delete();

    }

}

Вопросы:

  1. Что я делаю не так?(Т.е. я просто не могу смоделировать эту простую идею и пройти модульный тест. Как я уже говорил, новичок в Hibernate, и каждое внесенное мной изменение приводит к новому варианту ошибки Hibernate, который для меня ничего не значит. Например, этот текущийsetup бросает «отдельную сущность, переданную в persist: models.Node»)

  2. Изначально у меня был весь класс util в виде набора статических методов в классе модели.Во-первых, влияют ли статические методы на моделирование Hibernates?Если так, вкратце, при каких обстоятельствах я могу иметь статические методы (и члены, если подумать), которые будут «переходными» для моделирования объекта?

  3. Предполагая, что яхраните методы util в отдельном общедоступном классе util, где этот класс традиционно хранится в инфраструктуре воспроизведения?На данный момент он находится в пакете моделей, рядом с Node.java.

1 Ответ

2 голосов
/ 21 февраля 2011

Я не знаком с Play Framework, но могу кое-что сказать о работе с Hibernate:

  • Вы несете ответственность за поддержание согласованного состояния объектов в памяти. Рассмотрим следующий код:

    for(Node o : root.children)
        o.delete();
    root.save();
    

    Вы дали указание Hibernate удалить дочерние элементы из базы данных, но объект root в памяти все еще ссылается на них. Поскольку отношения настроены с помощью каскадирования, Hibernate попытается сохранить их снова (я полагаю, это является причиной ошибки «отсоединенная сущность передана для сохранения»). Таким образом, поддерживайте согласованное состояние объекта в памяти, очищая root.children.

  • Hibernate в значительной степени опирается на концепцию Единица работы . Я не уверен, как Play управляет этим, но похоже, что вы должны вызывать clearJPASession() в юнит-тестах, чтобы убедиться, что существующее состояние сеанса не повлияет на дальнейшие операции:

    root.save();
    
    clearJPASession();
    
    // test delete
    root = NodeUtil.getRoot(TEST_MENU);
    
  • Способ определения отношения поддерживается, но не рекомендуется (см. 2.2.5.3.1.1. Двунаправленный ). Вместо этого используйте следующий подход:

     @OneToMany(mappedBy = "parent", cascade=CascadeType.ALL, fetch=FetchType.EAGER)                           
     public List<Node> children = new LinkedList<Node>();
    
     @ManyToOne
     @JoinColumn(name="parent")
     public Node parent;
    
  • Статические методы не влияют на Hibernate.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...