Карта JPA/Hibernate @OneToMany для иерархических данных Oracle

Скажем, у меня есть информация о родителях и потомках в таблице Organization следующим образом:

id name parent_id
1  A    1
2  A1   1
3  A2   1
4  A11  2

С Oracle я могу получить всех потомков или предков организации, используя «начать с/подключиться». Например, следующий sql получит все поддерево под «A», включая себя (т.е. A, A1, A2, A11)

select * from Organization start with id=1 connect by nocycle prior id=parent_id;

Или этот sql получит всех предков A11, включая себя (т.е. A11, A1, A)

with o_hier as (select o.id, o.parent_id, CONNECT_BY_ISCYCLE as lvl from Organization o start with id=4 connect by nocycle prior parent_id = id) select o.* from Organization o, o_hier where o.id = o_hier.id union all select o.* from Organization o, o_hier where o.id = o_hier.parent_id and o_hier.lvl = 1;

Теперь я хочу сопоставить эту таблицу с OrganizationEntity следующим образом:

@Entity
@Table(name = "Organization")
public class OrganizationEntity {

    //getter/setter omitted for readability

    @Id
    @Column(name = "ID")
    private String id;

    @Column(name = "NAME")
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @???
    List<OrganizationEntity> descendants = new ArrayList<>();

    @ManyToOne(fetch = FetchType.LAZY)
    @???
    List<OrganizationEntity> ancestors= new ArrayList<>();
}

Я знаю о возможной проблеме с производительностью, но можем ли мы сопоставить что-то подобное с помощью Hibernate/JPA?


person Luan Nguyen    schedule 13.02.2015    source источник


Ответы (1)


Это сложно. Вы можете использовать стандартные родительские и дочерние сопоставления.

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ID")
OrganizationEntity parent;

@OneToMany(fetch = FetchType.LAZY)
@mappedBy(mappedBy="parent")
List<OrganizationEntity> childern;

А затем используйте стандартные алгоритмы обхода дерева, чтобы получить всех предков (простой цикл while) или всех потомков (некоторый вариант DFS, обычно в предварительном порядке).

С точки зрения исполнения эта рана будет очень медленной.

Другая и лучшая идея - просто выполнить обход в базе данных с помощью CONNECT BY, а затем сопоставить набор результатов с объектами. Вы можете сделать это с помощью чистых вызовов JPA или Специальные вызовы гибернации.

person dimm    schedule 14.02.2015
comment
Я заинтересован в выполнении рекурсивных вызовов в Oracle, как и ваша вторая идея, но, похоже, не могу заставить JoinColumnsOrFormula и/или JoinFormula, JoinColumn заставить его работать. Здесь есть черный пояс по Hibernate/JPA? - person Luan Nguyen; 15.02.2015
comment
@LuanNguyen просто использует собственный SQL-запрос, как описано здесь (чистый JPA) или здесь (зависит от режима гибернации). Я обновлю свой ответ. - person dimm; 15.02.2015
comment
Это можно сделать как запросы, но меня интересует решение, использующее только сопоставление. - person Luan Nguyen; 16.02.2015