JPA es algo con lo que trabajamos de forma habitual. Una parte del trabajo que tenemos que realizar es construir el modelo de dominio que normalmente lleva una esfuerzo inicial importante . Sin embargo cuando estamos construyendo la aplicación el modelo de dominio suele estar ya asentado y el mayor esfuerzo de desarrollo pasa por construir las diferentes consultas a realizar contra el modelo.
Consultas
Uno de los problemas que nos podemos encontrar cuando construimos las consultas es que varios desarrolladores van a trabajar en el mismo proyecto construyendo consultas. Con lo cual puede que acabemos con consultas repetidas en distintas partes del código .
Para evitar este problema podemos apoyarnos en JPA NamedQueries que nos permiten definir las consultas a nivel de clase de dominio evitando las repeticiones.
Vamos a verlo a través de un ejemplo en código:
package com.arquitecturajava; import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; @Entity @NamedQueries({ @NamedQuery(name="AlumnosNombre", query="select a from Alumno a where a.nombre=:nombre") }) public class Alumno implements Serializable{ private static final long serialVersionUID = 1L; @Id private String dni; private String nombre; private String apellidos; private int edad; public Alumno() { super(); } public Alumno(String dni, String nombre, String apellidos, int edad) { super(); this.dni = dni; this.nombre = nombre; this.apellidos = apellidos; this.edad = edad; } public String getDni() { return dni; } public void setDni(String dni) { this.dni = dni; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public String getApellidos() { return apellidos; } public void setApellidos(String apellidos) { this.apellidos = apellidos; } public int getEdad() { return edad; } public void setEdad(int edad) { this.edad = edad; } }  
En este caso hemos definido una clase Alumno y una NamedQuery denominada “AlumnosNombre” que nos busca a los alumnos por nombre. Una vez hecho esto podemos usar JPA y realizar la consulta en un programa sencilla.
package com.arquitecturajava.main; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.TypedQuery; import com.arquitecturajava.Alumno; public class Principal003SeleccionAlumnosWhereNamed2 { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("UnidadCurso"); EntityManager em = emf.createEntityManager(); TypedQuery<Alumno> consultaAlumnos= em.createNamedQuery("seleccionarAlumnosNombre", Alumno.class); consultaAlumnos.setParameter("nombre", "miguel"); List<Alumno> lista= consultaAlumnos.getResultList(); System.out.println("*************Alumnos*********"); for (Alumno a :lista) { System.out.println(a.getNombre()+"," +a.getApellidos()); } em.close(); System.out.println("termino"); } }
En este caso hemos usado el EntityManager y su método createNamedQuery para referenciar a la consulta que hemos definido a nivel de la clase Alumno a través de las anotaciones.
Otros artículos relacionados:
Dentro del mundillo de JPA lo que mejor funciona son las native querys ya que las querys JPA en si tienen serios problemas performance, lamentablemente si usamos native querys no se justifique el usar JPA.
El uso de native queries suele ser reducido para asegurar portabilidad. Las queries de JPA no debieran dar problemas si uno las configura correctamente
hola tengo una consulta, yo necesito realizar un mapero en JPA de una tabla que no tiene llave primaria, es esto posible ? gracias de antemano.
No lo he probado pero yo intentaría usar una native query no deberia dar problemas
Como es una native query?
Hola, me pueden ayudar en algo? el resultado de las consultas que realizo pueden ser de clases no entity? es para realizar consultas definidas en un campo de una tabla de la bd, estas consultas tienen el estandar de devolver solo dos campos.
Buenas puedes usar una consulta que devuelva un DTOaqui un ejemplo
Perfecto, me sirvió mucho. gracias
de nada 🙂
como puedo hacer una una @NamedQuery propia, por ej, quiero capturar el id de una sub tabla?
por ej tengo esto pero no retorna nada de esa consulta
“Usuario.findByCategoria”, query = “SELECT u FROM Usuario u WHERE u.categoria.id = :id”),
osea usuario tiene un campo categoria y categoria es otra tabla con varios campos pero solo me interesa el ID
no se si me explico
SALUDOS!
select u.id from Usuario u , te devolvera el id , sino recuerdo mal 🙂
Hola muchas gracias por tan buena explicación, veo que el nombre de la clase y el nombre de la tabla son el mismo, y esto me funciona bien para realizar consultas en una sola tabla, pero y si la query que necesito implementar es un poco más compleja y se debe consultar tres tablas al tiempo cómo sería? ¿es posible realizar esto mediante éste método?
Quedo atento a tu respuesta, de antemano muchas gracias y felicitaciones por esta página, explicaciones muy claras y una interfaz muy limpia y agradable.
No hay ningún problema para ejecutarlo , necesitarias realizar un join
Saludos! De vuelta por acá. Tenía abandonado el aprendizaje de Java con tu libro pero después de algunas semanas he vuelto a leerlo y avanzar un poco más; ahora mismo estoy en el capítulo 17 donde explicas de forma magistral el uso del patrón de Inyección de Dependencias. Me encuentro con un error después de haber seguido las instrucciones que das en el capítulo; por lo que entiendo es un problema con el contexto pero no sé como solucionarlo: FALLO – Apliación desplegada en la ruta de contexto /ArquitecturaJava, pero el contexto no pudo arrancar C:\Users\pc\workspace\ArquitecturaJava\nbproject\build-impl.xml:1100: The module has not… Read more »
El despliegue anterior lo intenté en Tomcat pero en GlassFish (que es que he venido utilizando) el error se muestra como: Starting GlassFish Server 3.1 GlassFish Server 3.1 is running. In-place deployment at C:\Users\pc\workspace\ArquitecturaJava\build\web Initializing… deploy?DEFAULT=C:\Users\pc\workspace\ArquitecturaJava\build\web&name=ArquitecturaJava&contextroot=/ArquitecturaJava&force=true failed on GlassFish Server 3.1 Error durante la implementación: Excepción al implementar la aplicación [ArquitecturaJava] : org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Archivo del descriptor de implementación WEB-INF/web.xml en el archivo de almacenamiento [web]. El contenido no está permitido en el prólogo.. Consulte /server.log para obtener más información. C:\Users\pc\workspace\ArquitecturaJava\nbproject\build-impl.xml:1100: The module has not been deployed. See the server log for details. BUILD FAILED (total time:… Read more »
No te se decir ya lo siento revisa bien pero parece un problema de tu servidor 🙁
Saludos Cecilio.
He avanzado un poco el tema que te planteé y resolví algunas cosas. Ahora estoy enfrentando otro problema y es al momento de modificar un objeto Libro. Me lanza el error de que estoy duplicando una entidad.
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry ‘1010’ for key ‘isbn’
Y esto tampoco lo entiendo porque el ISBN no es una clave de mi tabla en BD sino el id como se puede apreciar en los comentarios más arriba.
Gracias de antemano.
pues el error es claro lo tienes asigando como clave primaria revisa con la instruccion “describe” de mysql como se creo la tabla
Eh, ¿a qué te refieres? ¿Al id o al isbn? El id es PK de mi tabla libro, no así el isbn.
Ya resolví el problema. Estaba utilizando un constructor de la clase Libro que no debía para crear el objeto que iba a guardar en BD. Éste constructor no recibía el id:
Libro libro = new Libro(Integer.parseInt(isbn), titulo, categoriaObjeto);
Utilicé en su lugar:
Libro libro = new Libro(Integer.parseInt(id), Integer.parseInt(isbn), titulo, categoriaObjeto);
Y ahora marcha bien.
Gracias Cecilio. Estaré escribiendo seguido por aquí. Me es muy útil ayuda.
Saludos Cecilio. Primero que todo felicitarte por el esfuerzo y compartir tus sólidos conocimientos en materia de arquitectura de software implementando sobre Java. No he encontrado dónde hacer esta pregunta en todo tu blog por lo que buscando en tus post resolver mi problema di con esta entrada. Vengo leyendo tu libro (que me parece buenísimo) y desde hace algún tiempo tengo un problema que no me deja avanzar; estoy en el capítulo 14. He revisado y comparado el código con el que has puesto para descarga y está igual pero el problema sigue ahí y es el siguiente error… Read more »
Se me ocurren que igual no estas usando el Jar de JPA que suele traer hibernate como librería adicional para soportar JPA o bien estas usando JPA 1.0 que no soporta type queries 🙂 . Es lo primero que se me ocurre 🙂
Gracias Cecilio! Efectivamente, se trataba de la versión de la JPA que estaba utilizando. Eliminé todas las bibliotecas que estaban en el path de la aplicación y las incluí nuevamente una por una, asegurándome de colocar la versión correcta de la JPA y todo funcionó. Sólo que ahora tengo un error distinto cuando intento editar los datos de un libro: Provided id of the wrong type for class com.arquitecturajava.modelo.dto.Libro. Expected: class java.lang.Integer, got class java.lang.String Te comento, en la BD el tipo de datos de la columna isbn es Varchar que mapeo como String en el modelo Libro, quedando así:… Read more »
Da la sensación que has mapeado el isbn como integer y debiera ser String
Eso es lo que dice el error pero me he asegurado de que mapeo el ISBN como String y en la BD lo tengo como varchar.
La aplicación sigue arrojando el error:
Provided id of the wrong type for class com.arquitecturajava.modelo.dto.Libro. Expected: class java.lang.Integer, got class java.lang.String
y como tienes el id que es la clave primaria eso es lo que te da el error
También puedes hablar de los nativos que tienen su arandela
me apunto la idea 🙂