Usando el modelo de adyacencia simple donde cada fila contiene una referencia a sus padres que hará referencia a otra fila en la misma tabla no coopera bien con JPA. Esto se debe a que JPA no tiene soporte para generar consultas utilizando la cláusula Oracle CONNECT BY o la declaración WITH estándar de SQL. Sin cualquiera de esas 2 cláusulas, no es realmente posible hacer útil el Modelo de Adyacencia.
Sin embargo, hay un par de otros enfoques para modelar este problema que pueden aplicarse a este problema. El primero es Modelo de ruta materializada. Aquí es donde la ruta completa al nodo se aplana en una sola columna. La definición de la tabla se extiende de este modo:
CREATE TABLE node (id INTEGER,
path VARCHAR,
parent_id INTEGER REFERENCES node(id));
Para insertar un árbol de nodos se ve algo como:
INSERT INTO node VALUES (1, '1', NULL); -- Root Node
INSERT INTO node VALUES (2, '1.2', 1); -- 1st Child of '1'
INSERT INTO node VALUES (3, '1.3', 1); -- 2nd Child of '1'
INSERT INTO node VALUES (4, '1.3.4', 3); -- Child of '3'
Así que para obtener Nodo '1' y todos sus hijos la consulta es:
SELECT * FROM node WHERE id = 1 OR path LIKE '1.%';
Para asignar esto a JPA solo haga que la columna 'ruta' sea un atributo de su objeto persistente. Sin embargo, tendrá que hacer la contabilidad para mantener el campo 'ruta' actualizado. JPA/Hibernate no hará esto por usted. P.ej. si mueve el nodo a un elemento primario diferente, deberá actualizar la referencia principal y determinar el nuevo valor de ruta desde el nuevo objeto principal.
El otro enfoque se llama Conjunto anidado modelo, que es un poco más complejo. Probablemente sea el mejor described por su creador (en lugar de ser agregado textualmente por mí).
Hay un tercer enfoque llamado Modelo de intervalo anidado, sin embargo, esto tiene una gran dependencia de los procedimientos almacenados para implementar.
Una explicación mucho más completa de este problema se describe en el capítulo 7 de The Art of SQL.
Esto es bastante más complejo de lo que estaba buscando, pero gracias por la respuesta informativa. También hay una alternativa más simple al modelo de ruta materializada: haga que cada nodo almacene la ID del nodo raíz del árbol al que pertenece. Esto significa que solo puede usar el nodo raíz como punto de partida de la consulta, pero en mi caso específico eso no es un problema, así que probablemente sea eso lo que haré. –
Puede usar listas de adyacencia, administradas a través de JPA, pero use una consulta nativa para usar funciones SQL recursivas. Sería un poco asqueroso, y no portátil, pero sería algo así como lo mejor de ambos mundos. Los conjuntos anidados son portátiles, pero complicados, y no funcionan muy bien para algunos tipos de consultas bastante comunes. –
Ha cambiado algo con JPA 2.0 ... Por ejemplo, he usado una NamedQuery nativa para tener una cláusula 'CONNECT BY' en mi consulta. Lo he intentado y devuelve a los niños, pero no en una lista jerárquica ... Solo niños planos. ¿Algunas ideas? – SoftwareSavant