2010-04-08 17 views
8

Tengo una clase que modela todas las categorías y se pueden ordenar jerárquicamente.Consulta de JPA para obtener todo el árbol

@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; 

} 

tengo que conseguir todas las categorías ordenadas jerárquicamente (me refiero a todo padre seguido por sus hijos y padres ordenadas alfabéticamente en cada nivel), ya que podría hacerse, por ejemplo, con previo en el oráculo. ¿Es posible hacer esto con una consulta JPA (no SQL)?

Gracias.

+1

En su caso, supongo que necesita una relación de padres a hijos. Así que algo como '@OneToMany @JoinColumn (name =" idfather ") @OrderBy (value =" name ") private List children' te ayudará. Y luego buscar una categoría raíz cargará todo el árbol. –

+0

@dma_k Ya había tenido la misma Idea y después de saber que no era posible la consulta JPA que estaba haciendo de esta manera, gracias – Javi

+0

¿Pueden compartir con nosotros también el código Java, que realmente carga el árbol? Me pregunto cómo construyes/ejecutas la consulta JPA. También creo que si la capa de persistencia carga el árbol ejecutando una consulta para un nodo del árbol, debería saber cómo recuperar los elementos secundarios. Me pregunto cómo la extensión 'CONNECT BY PRIOR' de Oracle puede ayudarte aquí. –

Respuesta

7

La respuesta corta es; no, no hay una forma estándar de hacer esto.

Tienes que usar sql nativo.

Puede extender el dialecto de Hibernación de Oracle y agregar alguna función/extensión de usuario para obtener la hibernación para generar cláusulas PRIOR o CONNECT BY, pero esto evitará que su aplicación sea independiente de JPA estricta e independiente de la base de datos.

+0

Amplié Oracle Hibernate Dialect, pero no sé cómo agregarle mis funciones. podrías presentarme una muestra? –

+1

@RasoolGhafari lo siento, no puedo. Ha pasado tanto tiempo desde que me metí con los dialectos de Hibernate que más o menos he olvidado todo lo que sabía.Pero puede encontrar http://stackoverflow.com/questions/12346845/registering-a-sql-function-with-jpa-hibernate un buen punto de partida. –

1

En primer lugar, suponiendo que en esta jerarquía un "padre" puede tener más de un hijo, el campo father debe anotarse como @ManyToOne.

Si usted tiene un campo que todos los miembros de una cuota de árbol, o si el árbol contiene toda la tabla, entonces es posible hacerlo con la APP de una manera eficiente, aunque no a través de una sola consulta JPA .

sólo hay que precargar todos los miembros del árbol, y luego recorrer el árbol:

@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; 
} 

Aviso @OrderedBy la anotación en el campo subcategorías.

Ahora puede obtener todo el árbol cargando primero todas las categorías en una lista desordenada, solo para que todas estén en la memoria y luego atraviesen el árbol.

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); 
    } 
} 

sólo estoy aprendiendo APP mí en este momento, así que es posible que falte algo fundamental, pero este enfoque parece funcionar para mí.

+0

su solución no va a resolver el problema, considere tener miles de categorías y la cantidad de memoria necesaria para hacer esto, además necesitamos una solución para usarlo en otras consultas y combinaciones. – azerafati

Cuestiones relacionadas