JPA-запрос для получения всего дерева - PullRequest
8 голосов
/ 08 апреля 2010

У меня есть класс, который моделирует все категории, и их можно упорядочить иерархически.

@Entity
@Table(name="categories")
public class Category {
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequence")
    @SequenceGenerator(name="sequence", sequenceName="categories_pk_seq", allocationSize=1)
    @Column(name="id")
    private Long id;

    @Column
    private String name;

    @OneToOne
    @JoinColumn(name="idfather")
    private Category father;

}

Мне нужно упорядочить все категории иерархически (я имею в виду, что за каждым отцом следуют его дети и отцы, упорядоченные по алфавиту на каждомуровень), как они могут быть сделаны, например, с приорой в оракуле.Можно ли сделать это с помощью JPA Query (не SQL)?

Спасибо.

Ответы [ 2 ]

8 голосов
/ 08 апреля 2010

Краткий ответ: нет, не существует стандартного способа сделать это.

Вы должны использовать нативный sql.

Возможно, вы сможете расширить Oracle Hibernate Dialect и добавить некоторые пользовательские функции / расширения, чтобы перейти в спящий режим для генерации предложений PRIOR или CONNECT BY, но это помешает вашему приложению быть строгим JPA и независимым от базы данных.

1 голос
/ 03 марта 2011

Прежде всего, если в этой иерархии «отец» может иметь более одного потомка, то поле father должно быть аннотировано как @ManyToOne.

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

Вам просто нужно предварительно выбрать всех членов дерева, а затем пройти по дереву:

@Entity
@Table(name="categories")
public class Category {
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequence")
    @SequenceGenerator(name="sequence", sequenceName="categories_pk_seq", allocationSize=1)
    @Column(name="id")
    private Long id;

    @Column
    private String name;

    @ManyToOne
    @JoinColumn(name="idfather")
    private Category father;

    @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, 
               fetch = FetchType.LAZY, 
               mappedBy = "idfather")
    @OrderBy("name")
    private List<Category> subCategories;
}

Обратите внимание на аннотацию @OrderedBy в поле подкатегории.

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

public List<Category> getTree() {
    List<Category> jumbled = 
        entityManager.createQuery("from Category", Category.class).getResultList();

    Category root = null;
    for(Category category : jumbled) {
        if(category.getFather() == null) {
            root = category;
            break;
        }
    }

    List<Category> ordered = new ArratList<Category>();
    ordered.add(root);
    getTreeInner(root, ordered);
}

private void getTreeInner(Category father, List<Category> ordered) {
    for(Category child : father.getSubCategories()) {
        ordered.add(child);
        getTreeInner(child, ordered);
    }
}

Я только сейчас изучаю JPA, так что, может быть, я упускаю что-то решающее, но этот подход мне подходит.

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