Colección ordenada JPA/hibernate @OrderBy vs @Sort
@orderby jpa (3)
Me gustaría tener una colección de objetos secundarios (aquí el ejemplo de cat-gatito) que están ordenados. Y mantenga su orden añadiendo nuevos elementos.
@Entity
public class Cat {
@OneToMany(mappedBy = "cat", cascade = CascadeType.ALL)
@OrderBy("name ASC")
private List<Kitten> kittens;
public void setKittens(List<Kitten> kittens) { this.kittens = kittens; }
public List<Kitten> getKittens() { return kittens; }
}
Cuando hago cat.getKittens.add(newKitten)
la orden por nombre se romperá.
¿Es posible dejar que hibernate haga el trabajo de mantener la colección siempre ordenada? ¿Usando la anotación de hibernación @Sort ?
@Sort tiene la desventaja de que te obliga a implementar una interfaz comparable ... ¿Cuál sería la forma correcta de ''JPA puro'' para hacer eso? ¿Guardar todo en DB y volver a cargarlo? Tiene sentido combinar @OrderBy y @Sort?
La solución de actualización hasta ahora es combinar @OrderBy y @Sort. @OrderBy lleva a una cláusula ORDER BY
en el SQL generado que es mejor para el rendimiento (supongo que java está "ordenando" nuevamente al insertar en el contenedor ordenado, pero eso debería ser mucho más rápido porque los elementos ya están ordenados) @Sort juntos con una interfaz Comparable
implementada conduce a un contenedor siempre ordenado. Tenga en cuenta que utilizo SortedSet
lugar de List
. Aquí el Código actualizado:
@Entity
public class Cat {
@OneToMany(mappedBy = "cat", cascade = CascadeType.ALL)
@OrderBy("name ASC")
@Sort(type = SortType.NATURAL)
private SortedSet<Kitten> kittens;
public void setKittens(SortedSet<Kitten> kittens) { this.kittens = kittens; }
public SortedSet<Kitten> getKittens() { return kittens; }
}
La última versión de Hibernate usa nuevas anotaciones para lograr esto:
@SortNatural
@OrderBy("name ASC")
private SortedSet<Kitten> kittens = new TreeSet<>();
Hay dos partes para esto:
- La anotación
@OrderBy
especifica que se debe agregar una cláusulaorder by
a la consulta de la base de datos al recuperar los registros relacionados. - La anotación
@SortNatural
asume queKitten
implementa la interfazComparable
y usa esa información al construir la instancia deTreeSet
. Tenga en cuenta que puede reemplazar esto con la anotación@SortComparator
, que le permite especificar una clase deComparator
que se pasará al constructorTreeSet
.
Consulte la documentación: docs.jboss.org/hibernate/orm/5.2/userguide/html_single/…
Si desea evitar las anotaciones no estándar, puede hacer que los kittens
utilicen una implementación de Collection
ordenada. Esto aseguraría que los kittens
siempre en orden. Algo como esto:
@Entity
public class Cat {
@OneToMany(mappedBy = "cat", cascade = CascadeType.ALL)
@OrderBy("name ASC")
private SortedSet<Kitten> kittens = new TreeSet<>();
}
Tenga en cuenta que este enfoque también requiere que Kitten
implemente Comparable
(alternativamente, podría pasar un Comparator
a su constructor TreeSet
). Además, estoy usando un Set
porque no conozco ninguna implementación de List
clasificada estándar y supongo que el Cat
no tiene ningún clon en su hoja = p.
Actualización: no estoy seguro de cuán quisquilloso es Hibernate con sus definiciones getter / setter, pero con EclipseLink he podido eliminar un setter por completo y ajustar la List
devuelta por mi getter en una llamada Collections.unmodifiableList(...)
. Luego definí métodos especiales para modificar la colección. Podría hacer lo mismo y forzar a las personas que llaman a usar un método de agregar elementos en orden ordenado. Si Hibernate se queja de no tener getter / setter, ¿tal vez podría cambiar el modificador de acceso? Supongo que se trata de hasta dónde estás dispuesto a llegar para evitar dependencias no estándar.
@Entity
public class Cat {
@OneToMany(mappedBy = "cat", cascade = CascadeType.ALL)
private Set<Kitten> kittens = new TreeSet<>();
}
No es necesario escribir
@OrderBy("name ASC")
Asegúrese de que Kitten Class implemente una interfaz comparable correctamente.