Agrupaciones en consultas con javax.persistence.criteria.CriteriaBuilder
Vamos a poner un par de ejemplos de uso del CriteriaBuilder en JPA para poder hacer consultas usando JpaSpecificationExecutor e incluso usar agrupaciones con groupBy.
Se van a ir poniendo las diferentes clases desde el Entity hasta el Service:
Entity de la tabla cuenta con un par de campos.
@Entity(name="cuentaEntity") @Table(name="CUENTA") public class CuentaEntity implements Serializable { @Id private Integer id; @Column(name="balance") private Integer balance; @Column(name="empresa") private String empresa; @Column(name="fecha") @Temporal(TemporalType.TIMESTAMP) private Date fecha; //getter setter }
Su correspondiente JPAMetalModelEntityProcessor, la vamos a utilizar para las consultas.
@Generated(value = "org.hibernate.jpamodelgen.JPAMetalModelEntityProcessor") @StaticMetamodel(CuentaEntity.class) public abstract class CuentaEntity_ { public static volatile SingularAttribute< CuentaEntity, Integer> id; public static volatile SingularAttribute< CuentaEntity, Integer> balance; public static volatile SingularAttribute< CuentaEntity, String> empresa; public static volatile SingularAttribute< CuentaEntity, Date> fecha; }
Un clase repositorio. Hay que hacer que herede tanto de la JpaRepository como del JpaSpecificationExecutor.
@Repository public interface CuentaRepository extends JpaRepository< CuentaEntity, Integer>, JpaSpecificationExecutor< CuentaEntity> { }
Creamos nuestra clase criteria donde meteremos las especificaciones de las querys. Se añaden unos ejemplos de condicionales
public class CuentaCriteria implements Serializable{ private Integer id; private Integer balance; private String empresa; private Date fecha; ...... public static Specification< CuentaEntity> search(final CuentaCriteria cri){ return new Specification< CuentaEntity>(){ @Override public Predicate toPredicate(Root< CuentaEntity> root, CriteriaQuery< ?> criQuery, CriteriaBuilder criBuilder) { List< Predicate> predicates = new ArrayList< Predicate>(); //el nombre de la empresa sea igual al que se pasa en CuentaCriteria. Si no está vacia. if( !StringUtils.isEmpty( cri.getEmpresa())){ predicates.add( criBuilder.like(root.get(CuentaEntity_.empresa), cri.getEmpresa()) ); } //la fecha debe ser igual a la que se pasa en CuentaCriteria. Si no está vacia. if( !StringUtils.isEmpty( cri.getFecha())){ predicates.add( criBuilder.equal(root.get(StatementEntity_.fecha),cri.getFecha()) ); } //podemos añadir tambien una condicion de tipo OR ( id = 0 OR id = 1). List< Predicate> predOr = new ArrayList< Predicate>(); predOr.add( criBuilder.equal(root.get(CuentaEntity_.id), 0) ); predOr.add( criBuilder.equal(root.get(CuentaEntity_.id), 1) ); predicates.add( criBuilder.or(predOr.toArray(new Predicate[predOr.size()]) ) ); //Si tubieramos un objeto Embeddable u otro tipo de objeto podriamos acceder //a las propiedades de ese objeto //predicates.add( criBuilder.like(root.get("OBJETO").get("CAMPO_OBJETO"), "qqqqqq") ); .............. //Concatenamos todos los predicados como ands return criBuilder.and(predicates.toArray(new Predicate[predicates.size()])); } }; } }
Interfaz con nuestro servicio con unos métodos de prueba.
public interface CuentaService{ public Page< CuentaEntity> find(CuentaCriteria criteria, Pageable pageable); public List< Object[]> findGroupBy(CuentaCriteria criteria); public Long count(CuentaCriteria criteria); ......... }
Y su implementación:
@Component("cuentaService") @Transactional public class CuentaServiceImpl implements CuentaService { @PersistenceContext EntityManager em; @Autowired private CuentaRepository cuentaRepository; //En este método permite realizar una consulta que devuelve el listado de todas las cuentas que //lo cumplen. Las condiciones de la consulta se le pasan con CuentaCriteria.search(criteria). //No devolverá todos los elementos al pasarle un objeto Pageable para paginación. public Page< CuentaEntity> find(CuentaCriteria criteria, Pageable pageable){ return cuentaRepository.findAll( CuentaCriteria.search(criteria), pageable); } //En este método deveulve la cuenta de la consulta anterior. Las condiciones de la consulta //se le pasan con CuentaCriteria.search(criteria). public Long count(StatementCriteria criteria){ return this.statementRepository.count( StatementCriteria.search(criteria) ); } //El groupBy no funciona bien si se mete en StatementCriteria.search(criteria), eso es porque //aunque hagas un multiselect() con sólo los elementos que quieres sacar en la consulta te lo va //a sobreescribir por el select(). //Una posible solución sería hacerlo como se hace en este método. public List< Object[]> findGroupBy(CuentaCriteria criteria){ CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery> cq = cb.createQuery(); Rootroot = cq.from(StatementEntity.class); //declaramos el multiselect con las columnas a devolver cq.multiselect( //fecha mayor cb.greatest( root.get(CuentaEntity_.fecha).as(java.util.Date.class) ), //fecha menor cb.least( root.get(CuentaEntity_.fecha).as(java.util.Date.class) ), //balance mayor cb.max( root.get(CuentaEntity_.balance) ), //balance menor cb.min( root.get(CuentaEntity_.balance) ), //media del balance cb.avg( root.get(CuentaEntity_.balance) ), //suma del balance total cb.sum( root.get(CuentaEntity_.balance).as(java.lang.Integer.class) ), //suma del balance siempre que sea mayor de cero, es decir, positivo cb.sum( cb. selectCase() .when(cb.greaterThan(root.get(CuentaEntity_.balance), 0), root.get(CuentaEntity_.balance) ).otherwise(0)), //contador con todas las filas agrupadas cb.count( root.get(CuentaEntity_.id) ) ); //aplicamos todas la condiciones de consulta al where cq.where( CuentaCriteria.search(criteria).toPredicate(root, cq, cb) ); //le decimos que agrupe por el nombre de las empresas cq.groupBy( root.get( CuentaEntity_.empresa) ); Query query = em.createQuery(cq); //Por último lo podemos retornar como una lista de objetos return (List< Object[]>)query.getResultList(); } }
Crear aplicación a partir de la Base de Datos con Spring Roo
Paso 1: Instalar Spring Roo
– En primer lugar necesitas tener instalado Java y Maven.
– A continuación te descargas Spring Roo de la página oficial.
– Se descomprime en un directorio y se añade al path. En windows seria añadir en el path $ROO_HOME\bin siendo $ROO_HOME el directorio donde lo has descomprimido.
– Para comprobar que se ha instalado correctamente podemos ejecutar directamente en la consola el siguiente comando.
roo quit
Si todo va bien debería mostrarnos el logo de Spring Roo.
Paso 2: Crear un proyecto de Spring Roo
Se puede crear de distintas formas:
– Con el STS se puede crear un proyecto de Spring Roo como tal.
– Con el eclipse también se podría añadiendo el plugin de Spring Roo.
– Y por último también podriamos utilizar directamente la consola para su creación.
De esta forma, los comandos para la creación de un proyecto a partir de una BD Mysql serían:
//Primero se configura la BD de la que luego se hará ingeniería inversa... jpa setup --database MYSQL --provider HIBERNATE --databaseName nombre_de_mi_esquema --hostName ip_de_mi_mysql --userName mi_usuario --password mi_contraseña
//Luego se puede comprobar si se ha realizaco la conexión bien database introspect --schema nombre_de_mi_esquema
// si te dice que no encuentra el driver puedes instalarlo así addon search mysql //te deberia salir una lista con los drivers que puedes instalar para a continuación addon install id --searchResultId xx //xx sería el codigo del driver mostrado en el listado que saca el anterior comando...
//En mi caso me dió problemas y el de mysql no me lo instaló bien así que lo instale a mano. //Para ello me lo descargue y lo instalé con el siguiente comando: osgi start --url file:///C:\\mysql-connector-java-5.1.18.jar
//Ahora ya se puede crear las entidades a partir de la BD. database reverse engineer --schema nombre_de_mi_esquema --package ~.domain --includeTables "tab_*"
Por último sería añadir el resto del negocio y la presentación. Para ello pongo dos ejemplos: MVC y JSF.
//Usando Spring MVC web mvc setup web mvc all --package ~.web
Usando JSF web jsf setup --implementation --library --theme web jsf all --package ~.web
Como nota decir que se lía algo con las tablas con clave primaria múltiple (hay que quitar unos errores que salen en los ficheros *.aj que crea).
Puedes probar a ejecutar el proyecto simplemente con la instrucción de manve
mvn clean install jetty:run
Documentación:
Ejemplo de creación de un proyecto con STS. Ver
Ejemplo de creación de un proyecto con el plugin de eclipse para Spring Roo. Ver
Tipos de generadores de identificadores en hibernate
En hibernate podemos utilizar el elemento generator para generar identificadores únicos para instancias de la clase persistente. De requerirse algún parámetro para configurar o inicializar la instancia del generador, se pasa utilizando el elemento .
Todos los generadores implementan la interfaz org.hibernate.id.IdentifierGenerator. Algunas aplicaciones pueden decidir brindar sus propias implementaciones especializadas. Sin embargo, Hibernate provee un rango de implementaciones ya incorporadas. Los nombres de atajo para los generadores incorporados son los siguientes:
increment: genera indentificadores de tipo long, short o int que sólamente son únicos cuando ningún otro proceso está insertando datos en la misma tabla. No lo utilice en un clúster.
identity: soporta columnas de identidad en DB2, MySQL, MS SQL Server, Sybase y HypersonicSQL. El identificador devuelto es de tipo long, short o int.
sequence: usa una secuencia en DB2, PostgreSQL, Oracle, SAP DB, McKoi o un generador en Interbase. El identificador devuelto es de tipo long, short o int.
hilo: utiliza un algoritmo alto/bajo para generar eficientemente identificadores de tipo long, short o int, dada una tabla y columna como fuente de valores altos (por defecto hibernate_unique_key y next_hi respectivamente). El algoritmo alto/bajo genera identificadores que son únicos sólamente para una base de datos particular.
seqhilo: utiliza un algoritmo alto/bajo para generar eficientemente identificadores de tipo long, short o int, dada una secuencia de base de datos.
uuid: utiliza un algoritmo UUID de 128 bits para generar identificadores de tipo cadena, únicos dentro de una red (se utiliza la direccón IP). El UUID se codifica como una cadena hexadecimal de 32 dígitos de largo.
guid: utiliza una cadena GUID generada por base de datos en MS SQL Server y MySQL.
native: selecciona identity, sequence o hilo dependiendo de las capacidades de la base de datos subyacente.
assigned: deja a la aplicación asignar un identificador al objeto antes de que se llame a save(). Esta es la estrategia por defecto si no se especifica un elemento < generator>.
select: recupera una clave principal asignada por un disparador de base de datos seleccionando la fila por alguna clave única y recuperando el valor de la clave principal.
foreign: utiliza el identificador de otro objeto asociado. Generalmente se usa en conjunto cón a una asociación de clave principal < one-to-one>.
sequence-identity: una estrategia de generación de secuencias especilizadas que utiliza una secuencia de base de datos para el valor real de la generación, pero combina esto junto con JDBC3 getGeneratedKeys para devolver el valor del identificador generado como parte de la ejecución de la declaración de inserción. Esta estrategia está soportada sólamente en los controladores 10g de Oracle destinados para JDK1.4. Los comentarios en estas declaraciones de inserción están desactivados debido a un error en los controladores de Oracle.
Ejemplo 1:
Si tenemos una clave primaria «idAplicacion» en MySQL con la propiedad auto_increment, se mapearia así:
//Mapeo usando anotaciones @Id @GeneratedValue private Integer idAplicacion; //Mapeo en fichero hbm < id name="idAplicacion" type="int" unsaved-value="0"> < column name="idAplicacion" precision="5" scale="0"/> < generator class="identity"/> < /id>
Ejemplo 2:
Si tenemos una clave primaria «idAplicacion» en una BD oracle y queremos asignarle una secuencia llamada SEQ_ID_APLICACION, se mapearía así:
//Mapeo usando anotaciones @Id @SequenceGenerator(name="seq", sequenceName="SEQ_ID_APLICACION") @GeneratedValue(strategy=GenerationType.AUTO, generator="seq") private Integer idAplicacion; //Mapeo en fichero hbmSEQ_ID_APLICACION
Plugin para el eclipse que genera aplicación automaticamente
En GitHub he creado un repositorio donde comparto un plugin para el eclipse que he implementado y que facilita el desarrollo aplicaciones J2EE https://github.com/roberto-pf/Sotilizator. El plugin consigue implementar toda la lógica de negocio de una aplicación que utiliza: Struts + Spring + hibernate + JQuery.
Qué es el Sotilizator?
Se trata de un plugin para el eclipse (probado en su versión Helios). La finalidad de este plugin es la creación de una aplicación web de forma automática y con unas determinadas características a partir de un esquema de una Base de Datos.
Estas características son:
1 – La aplicación resultante estará realizada empleando un MVC en J2EE con Struts 1.3, inyección de dependencias con Spring 3.0, hibernate 3.2.6 para el acceso a datos para la parte de la lógica de negocio. Mientras que para la parte de la vista se empleará jquery junto a las tag-libraries de struts. Además, de DWR para interactuar con el servidor desde el cliente.
2 – Se generará un fichero pom.xml para que a través de MAVEN se puedan obtener las dependencias.
3 – Se generará un fichero build.xml donde estarán las tareas Ant necesarias para el despliegue de la aplicación en Tomcat, JBoss y OAS.
4 – La aplicación resultante será capaz de construir las tareas CRUD de las tablas automáticamente. A partir del esquema de la BD obtendrá los campos y su tipo.
5 – Las capas que contendrá la aplicación son las siguientes:
VO: Objetos que hace referencias a las tablas. DAO: Capa que realiza el acceso a la BD. Manager: Capa sobre la que se aplican las transacciones. Delegate: Capa que se encarga de relacionar la parte de la vista con la lógica de negocio. Action: Aquí deberán ir las diferentes acciones que luego el controlador mapea para interactuar con la vista.
Nota: Para más información consultar manuales del usuario y del programador: https://github.com/roberto-pf/Sotilizator/tree/master/Readme
Categorias
- adobe (2)
- agile (1)
- Alfresco (1)
- Android (26)
- Angular (6)
- angularjs (10)
- apache (1)
- axis (2)
- Bases de datos (14)
- Bootstrap (1)
- C# (3)
- Cámara (1)
- chrome (3)
- Codeigniter (2)
- Control de Versiones (2)
- CSS (25)
- CVS (1)
- Django (9)
- Django Rest Framework (1)
- DNS (1)
- Docker (3)
- dominio (1)
- eclipse (5)
- Entity Framework (2)
- ETL (1)
- Firefox (6)
- flash (1)
- freecad (1)
- Git (12)
- GitHub (4)
- gpg (2)
- Groovy (1)
- Handlebars (1)
- hibernate (4)
- hosting (1)
- HTML (50)
- HTML 5 (26)
- Impresión 3D (9)
- Inkscape (1)
- IOS (2)
- ireports (3)
- Java (44)
- Javascript (55)
- JBoss (5)
- JPA (2)
- JQuery (20)
- Json (7)
- JSP (6)
- Keycloak (1)
- Lamp (1)
- LDAP (2)
- lean (1)
- linkedin (1)
- LINQ (1)
- linux (13)
- Livecycle (1)
- log (1)
- microcontroladores (1)
- MongoDB (4)
- MySQL (8)
- Node.js (5)
- OC4J (1)
- Openshift (2)
- Oracle (6)
- Patrones de Diseño (1)
- Photoshop (2)
- php (20)
- PostgreSQL (1)
- python (19)
- rabbitmq (1)
- Raspberry PI (13)
- Raspherry PI (5)
- React (6)
- seguridad (3)
- Selenium (3)
- Sencha Touch (1)
- Sin categoría (29)
- Spring (17)
- spring-boot (3)
- SQL (7)
- SQLServer (1)
- SSO (1)
- struts (2)
- SVN (1)
- Talend (1)
- Tomcat (6)
- unity (3)
- Visual Studio Code (2)
- vmware (5)
- Web Services (11)
- windows (18)
- wordpress (10)
- Xiaomi (1)
- xml (2)
Trabajos Realizados
- App Android – Autoka Fr
- App Android – Cartelera Cántabra
- App Android – Gramática y Vocabulario Ingles
- App Android – Hoja de Gastos
- App Android – Hotel Torre Cristina
- App Android – OcioEnjoy
- App Android – Visor CardBoard
- App Firefox – Managapp
- DiamanteBomba – DisasterCode
- Generador de Partes de Trabajo
- GitHub – Android Web Generator
- GitHub – Dynamic Angular Gallery
- GitHub – Dynamic React Gallery
- GitHub – Sotilizator
- GitHub – SpringAngularJS
- GitHub – Swiper Dynamic Angular Gallery
- HazParejas – DisasterCode
- RompeCabezas – DisasterCode
- Unity Game – English Couple
- Unity Game – Kill Wasp
- WordPress – El Buen Apicultor
- WordPress – El Cajón de los Retales
- WordPress – El Vestidito Azul
- WordPress – Feuchas
- WordPress – Fragua de Navajas Ponce
- WordPress – Humor a las Tres
- WordPress – Photo Places