Загрузка родительской / дочерней иерархии с управляющими листами гибернации - PullRequest
2 голосов
/ 07 сентября 2011

Я пытаюсь загрузить из базы данных граф родительских / дочерних объектов (аналогично объекту DefaultMutableTreeNode в Java).Между двумя существует простая связь один ко многим. Общее число уровней графа известно, поэтому я точно знаю, сколько раз вызывать метод getChildren ().То, что я хочу сделать, это не вызывать этот метод для фактических конечных узлов.Обычно граф состоит из нескольких неконечных узлов и нескольких сотен листовых узлов.Если я указываю lazy=false в отображении hb, я получаю сотни ненужных запросов от hb для дочерних узлов листьев, тогда как я заранее знаю, что они не нужны (так как я знаю общее количество уровней в дереве).К сожалению, я не могу использовать lazy=true и выполнять цикл только до тех пор, пока не будут созданы родительские узлы, потому что я работаю над отключенной моделью клиент / сервер и использую beanlib для загрузки всего графа объектов (который содержит несколько других объектов).

Поэтому я пытаюсь найти способ перехватить загрузку коллекции 'children' и дать команду hb остановиться, когда она достигнет конечных узлов.Есть способ сделать это?Я смотрю на 2 решения: я имею в виду следующее: когда я вызываю метод node.getChildren() (в рамках сеанса hb), обычно hb выполняет запрос db для получения дочерних элементов: есть ли способ перехватить этот вызови просто не сделать это?Я знаю, что детей нет, поэтому я просто хочу, чтобы он быстро провалился (на самом деле я вообще не хочу этого делать).

Спасибо, Костас

Ответы [ 3 ]

1 голос
/ 07 сентября 2011

Почему бы вам просто не использовать логическое свойство leaf и заставить ваш метод getChildren возвращать пустой список, если leaf имеет значение true?

private boolean leaf;

private List<Node> children;

public List<Node> getChildren() {
    if (leaf) {
        return Collection.<Node>emptyList();
    }
    return children;
}
0 голосов
/ 10 ноября 2011

Вы можете использовать AOP для рекомендаций по вызову getChildren, который делает что-то вроде этого (обратите внимание, это очень грубый псевдо-код, вам придется заполнить «пробелы»):

childrenResult = node.getChildren()
if (Hibernate.isInitialized(childrenResult)) {
    return node.getChildren()
} else {
  // Do something else here
}

Это будет происходить, когда вы делаете вызов getChildren, и коллекция не инициализируется, она может быть принята или не разрешена для продолжения обработки.Однако, если элемент инициализирован, он позволит продолжить вызовы.В Hibernate.isInitialized следует обратить внимание на то, что он возвращает true во ВСЕХ объектах, но в отложенных загруженных коллекциях, которые еще не были заполнены.

Если вы не можете использовать AOP, вы всегда можете выполнить эту проверкупо вашему собственному вызову getChildren в вашем коде.

0 голосов
/ 07 сентября 2011

Если ваша база данных не связана с java-кодом, выполняющим эти запросы, вероятно, узким местом является производительность для запроса на узел, даже если это просто запрос на внутренний узел.Поскольку вам известны максимальные уровни дерева (для примера предположим 3), следующее должно извлечь все дерево в одном запросе:

from Node n1
left join n1.children as n2
left join n2.children as n3
left join n3.children as n4

Недостатком этого метода является то, чтоresultset будет повторять данные для каждого внутреннего узла для каждого из его потомков, т.е. взятая полоса умножается на количество уровней дерева.Если это проблема, потому что у вас много уровней, вы можете включить пакетную выборку для этой коллекции или даже сделать что-то подобное вручную:

List<Node> border = Collections.singletonList(rootNode);
while (!border.isEmpty()) {
    List<Integer> ids = new ArrayList<Integer>();
    for (Node n : border) {
        ids.add(n.getId());
    }

    // initialize the children collection in all nodes in border
    session.createQuery("from Node n left join n.children where n.id in ?").setParameter(0, ids).list();

    List<Node> newBorder = new ArrayList<Node>();
    for (Node n : border) {
        newBorder.addAll(n.getChildren());
    }
    border = newBorder;
}

Это выдаст столько запросов, сколько уровней в дереве.и передать данные для каждого узла дважды.(Некоторые базы данных ограничивают размер встроенного предложения. Тогда вам придется пакетировать в пределах уровня)

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