query jparepository example data java jpa criteria dao

java - jparepository - JPA-FindByExample



native query jpa repository (7)

¿Alguien tiene un buen ejemplo de cómo hacer un findByExample en JPA que funcione dentro de un DAO genérico a través de la reflexión para cualquier tipo de entidad? Sé que puedo hacerlo a través de mi proveedor (Hibernate), pero no quiero romper con la neutralidad ...

Parece que la API de criterios podría ser el camino a seguir ... pero no estoy seguro de cómo manejar la parte de reflexión.


Criteria API es su mejor apuesta. Sin embargo, necesitará un proveedor JPA-2.0 para eso. Entonces, si tienes una entidad como esta:

@Entity public class Foo { @Size(max = 20) private String name; }

La siguiente prueba unitaria debería tener éxito (la probé con EclipseLink, pero debería funcionar con cualquiera de los proveedores JPA-2.0):

@PersistenceContext private EntityManager em; @Test @Transactional public void testFoo(){ Foo foo = new Foo(); foo.setName("one"); em.persist(foo); CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Foo> c = cb.createQuery(Foo.class); Root<Foo> f = c.from(Foo.class); c.select(f).where(cb.equal(f.get("name"), "one")); TypedQuery<Foo> query = em.createQuery(c); Foo bar = query.getSingleResult(); Assert.assertEquals("one", bar.getName()); }

Además, es posible que desee seguir el enlace al tutorial al que se hace referencia here .



En realidad, se ha considerado la inclusión de Query By Example (QBE) en la especificación JPA 2.0, pero no se incluye, incluso si los principales proveedores lo admiten. Citando a Mike Keith:

Lamento decir que en realidad no pudimos hacer QBE en JPA 2.0. Criteria API no tiene ningún operador especial para él, por lo que la igualdad de la entidad es igual que en JP QL, en función del valor de PK. Lo sentimos, pero esperamos tener más éxito en ese frente en la próxima ronda. Por ahora es una de esas características de proveedor que todos los proveedores admiten, pero aún no está en la especificación.

Por las dudas, he agregado código de ejemplo (no genérico) para los principales proveedores a continuación para fines de documentación.

EclipseLink

Aquí hay una muestra del uso de QBE en la implementación de referencia EclipseLink JPA 2.0:

// Create a native EclipseLink query using QBE policy QueryByExamplePolicy policy = new QueryByExamplePolicy(); policy.excludeDefaultPrimitiveValues(); ReadObjectQuery q = new ReadObjectQuery(sampleEmployee, policy); // Wrap the native query in a standard JPA Query and execute it Query query = JpaHelper.createQuery(q, em); return query.getSingleResult();

OpenJPA

OpenJPA admite este estilo de consulta a través de su interfaz extendida OpenJPAQueryBuilder :

CriteriaQuery<Employee> q = cb.createQuery(Employee.class); Employee example = new Employee(); example.setSalary(10000); example.setRating(1); q.where(cb.qbe(q.from(Employee.class), example);

Hibernar

Y con la API de criterios de Hibernate:

// get the native hibernate session Session session = (Session) getEntityManager().getDelegate(); // create an example from our customer, exclude all zero valued numeric properties Example customerExample = Example.create(customer).excludeZeroes(); // create criteria based on the customer example Criteria criteria = session.createCriteria(Customer.class).add(customerExample); // perform the query criteria.list();

Ahora, si bien debería ser posible implementar algo que se acercara de forma neutral a los proveedores con JPA 2.0 Criteria API y la reflexión, realmente me pregunto si vale la pena el esfuerzo. Quiero decir, si hace genéricos algunos de los fragmentos anteriores y coloca el código en un método DAO, sería muy fácil cambiar de un proveedor a otro si fuera necesario. Estoy de acuerdo que no es ideal, pero aún así.

Referencias


Esto es bastante crudo y no estoy seguro de que sea una buena idea en primer lugar. Pero de todos modos, intentemos implementar QBE con la API de criterios JPA-2.0.

Comience definiendo una interfaz Persistable:

public interface Persistable { public <T extends Persistable> Class<T> getPersistableClass(); }

El método getPersistableClass() está ahí porque el DAO necesitará la clase, y no pude encontrar una manera mejor de decir T.getClass() más adelante. Sus clases modelo implementarán Persistable :

public class Foo implements Persistable { private String name; private Integer payload; @SuppressWarnings("unchecked") @Override public <T extends Persistable> Class<T> getPersistableClass() { return (Class<T>) getClass(); } }

Entonces su DAO puede tener un findByExample(Persistable example) (EDITED):

public class CustomDao { @PersistenceContext private EntityManager em; public <T extends Persistable> List<T> findByExample(T example) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { Class<T> clazz = example.getPersistableClass(); CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<T> cq = cb.createQuery(clazz); Root<T> r = cq.from(clazz); Predicate p = cb.conjunction(); Metamodel mm = em.getMetamodel(); EntityType<T> et = mm.entity(clazz); Set<Attribute<? super T, ?>> attrs = et.getAttributes(); for (Attribute<? super T, ?> a: attrs) { String name = a.getName(); String javaName = a.getJavaMember().getName(); String getter = "get" + javaName.substring(0,1).toUpperCase() + javaName.substring(1); Method m = cl.getMethod(getter, (Class<?>[]) null); if (m.invoke(example, (Object[]) null) != null) p = cb.and(p, cb.equal(r.get(name), m.invoke(example, (Object[]) null))); } cq.select(r).where(p); TypedQuery<T> query = em.createQuery(cq); return query.getResultList(); }

Esto es bastante feo. Supone que los métodos getter se pueden derivar de los nombres de los campos (esto es probablemente seguro, como por ejemplo un Java Bean), la manipulación de cadenas en el bucle y puede arrojar un montón de excepciones. La mayor parte del clunkiness en este método gira en torno al hecho de que estamos reinventando la rueda. Tal vez haya una mejor manera de reinventar la rueda, pero tal vez sea allí donde debemos reconocer la derrota y recurrir a uno de los métodos enumerados anteriormente por Pascal. Para Hibernate, esto simplificaría la interfaz para:

public interface Persistable {}

y el método DAO pierde casi todo su peso y clunkiness:

@SuppressWarnings("unchecked") public <T extends Persistable> List<T> findByExample(T example) { Session session = (Session) em.getDelegate(); Example ex = Example.create(example); Criteria c = session.createCriteria(example.getClass()).add(ex); return c.list(); }

EDITAR: Entonces la siguiente prueba debería tener éxito:

@Test @Transactional public void testFindFoo() { em.persist(new Foo("one",1)); em.persist(new Foo("two",2)); Foo foo = new Foo(); foo.setName("one"); List<Foo> l = dao.findByExample(foo); Assert.assertNotNull(l); Assert.assertEquals(1, l.size()); Foo bar = l.get(0); Assert.assertNotNull(bar); Assert.assertEquals(Integer.valueOf(1), bar.getPayload()); }


Quizás la respuesta sea demasiado tarde. Pero mira esto Puede ser de ayuda.

https://sourceforge.net/projects/simplejpaquery/

Primero, incluye el jar en classpath. Tendrás una clase llamada com.afifi.simpleJPAQuery.entities.utility.JPAUtil . Esta clase usa la reflexión para deducir la consulta del bean. Supongamos que tiene un bean de entidad de la siguiente manera:

@Entity public class Person { @Id private Integer personNo; private String personName; public Integer getPersonNo() { return personNo; } public void setPersonNo(Integer personNo) { this.personNo = personNo; } public String getPersonName() { return personName; } public void setPersonName(String personName) { this.personName = personName; } }

Entonces, si desea consultar por nombre de persona, por ejemplo, debe hacer lo siguiente:

//initiate entity manager (em) Person p=new Person(); p.setPersonName("John"); String sortString=""; List<Person> result= JPAUtil.findByExample(em,p,sortString);

El resultado obtendrá todos los registros donde el nombre de la persona contenía la palabra "John".

si quiere limitar los resultados, puede hacer algo como:

List<Person> result= JPAUtil.findByExample(em, p, sortString, start, size);

Esta biblioteca tiene otros métodos como:

getResultCount : para obtener el recuento del resultado

createSqlStatement : para obtener la sentencia sql que se está utilizando

getSqlWhereString : para obtener solo la cadena utilizada

Tiene las formas nativas de estas funciones:

findByExampleNative , getResultCountNative , createSqlStatementNative y getSqlWhereStringNative

La biblioteca también tiene la clase QueryAnnotations que contiene anotaciones que se pueden agregar a las propiedades de bean de la entidad para dar más control sobre cómo desea realizar consultas utilizando el bean.


puedes usar esto https://github.com/xiaod0510/jpa-findbyexample

si su entidad es Contacto:

@Entity public class Contact { @Id @GeneratedValue private Long id; @Column private String name; @Column private Date birthday; //Getter and Setter } public interface ContactRepository extends JpaSpecificationExecutor<Contact> { }

solo crea tu propio ejemplo como este:

public class ContactExample extends BaseExample<ContactExample, Contact> { public final Attr<Long> id = new Attr<Long>("id"); public final Attr<String> name = new Attr<String>("name"); public final Attr<Date> birthday = new Attr<Date>("birthday"); //default builder public static ContactExample where() { ContactExample example = new ContactExample(); example.operatorType = OperatorType.and; return example; } }

y ahora puedes consultar por ejemplo:

ContactRepository.findOne(ContactExample .where()//default is and .id.eq(1l) );

el ejemplo implementa la interfaz "Especificación", más información sobre ese github


https://github.com/superbiger/sbiger-jpa-qbe

Creo que la consulta por ejemplo con una sola tabla como mybatis es fácil de usar

base en jpa también podemos apoyar Join / GroupBy así:

/* SQL: select * from user where id=1 or id=2 group by id, name order by id asc, name asc limit ? */ public List<User> findAll(){ Example<User> example = ExampleBuilder.create(); example.or() .andEqual("id", 1) .orEqual("id", 2); example.groupBy("id","name"); example.asc("id","name"); return userReponsitory.findAll(example, new PageRequest(0, 1)); }

Características ahora:

  • Soporte y / o operación lógica
  • El soporte es (Vacío / Booleano / Nulo)
  • Soporte Equal / NotEqual / In / NotIn / Me gusta / NotLike
  • Soporte gt / ge / lt / le / entre
  • Soporte unirse consulta
  • Grupo de apoyo por
  • Soporte de especificación personalizada.
  • Paginación de soporte
    más características próximamente ...