pagingandsortingrepository mkyong example ejemplo data crudrepository java spring jpa spring-data spring-data-jpa

java - mkyong - spring data jpa jpql



Uso de genéricos en repositorios JPA de Spring Data (1)

Tengo una cantidad de tipos de objetos simples que necesitan persistir en una base de datos. Estoy usando Spring JPA para administrar esta persistencia. Para cada tipo de objeto, necesito construir lo siguiente:

import org.springframework.data.jpa.repository.JpaRepository; public interface FacilityRepository extends JpaRepository<Facility, Long> { } public interface FacilityService { public Facility create(Facility facility); } @Service public class FacilityServiceImpl implements FacilityService { @Resource private FacilityRepository countryRepository; @Transactional public Facility create(Facility facility) { Facility created = facility; return facilityRepository.save(created); } }

Se me ocurrió que podría ser posible reemplazar las múltiples clases para cada tipo de objeto con tres clases basadas en genéricos, ahorrando así una gran cantidad de códigos repetitivos. No estoy exactamente seguro de cómo hacerlo y, de hecho, si es una buena idea.


En primer lugar, sé que estamos elevando el listón un poco, pero esto ya es mucho menos código de lo que tenía que escribir sin la ayuda de Spring Data JPA.

En segundo lugar, creo que no necesita la clase de servicio en primer lugar, si todo lo que hace es reenviar una llamada al repositorio. Recomendamos el uso de servicios frente a los repositorios si tiene una lógica comercial que necesita la orquestación de repositorios diferentes dentro de una transacción o tiene otra lógica comercial para encapsular.

En términos generales, puede hacer algo como esto:

interface ProductRepository<T extends Product> extends CrudRepository<T, Long> { @Query("select p from #{#entityName} p where ?1 member of p.categories") Iterable<T> findByCategory(String category); Iterable<T> findByName(String name); }

Esto le permitirá usar el repositorio en el lado del cliente de esta manera:

class MyClient { @Autowired public MyClient(ProductRepository<Car> carRepository, ProductRepository<Wine> wineRepository) { … } }

y funcionará como se esperaba. Sin embargo, hay algunas cosas que notar:

Esto solo funciona si las clases de dominio usan herencia de tabla única. La única información sobre la clase de dominio que podemos obtener en el momento de arranque es que serán objetos del Product . Entonces para métodos como findAll() e incluso findByName(…) las consultas relevantes comenzarán con select p from Product p where… Esto se debe al hecho de que la búsqueda de reflejo nunca podrá producir Wine o Car menos que se cree una interfaz de repositorio dedicada para capturar la información de tipo concreto.

En general, recomendamos crear interfaces de repositorio por raíz agregada . Esto significa que no tiene un repositorio para cada clase de dominio per se. Aún más importante, una abstracción 1: 1 de un servicio sobre un repositorio tampoco tiene sentido. Si construyes servicios, no construyes uno para cada repositorio (un mono podría hacer eso, y nosotros no somos monos, ¿verdad?). Un servicio expone una API de nivel más alto, es mucho más unidad de caso de uso y generalmente orquesta llamadas a múltiples repositorios.

Además, si crea servicios en los repositorios, generalmente quiere exigir a los clientes que usen el servicio en lugar del repositorio (un ejemplo clásico es que un servicio para la administración de usuarios también desencadena la generación de contraseñas y el cifrado, de modo que de ninguna manera sería una buena idea dejar que los desarrolladores usen el repositorio directamente, ya que trabajarían efectivamente alrededor del cifrado). Por lo tanto, generalmente es necesario ser selectivo sobre quién puede persistir qué objeto de dominio para no crear dependencias en cualquier lugar.

Resumen

Sí, puede crear repositorios genéricos y usarlos con múltiples tipos de dominio, pero existen limitaciones técnicas bastante estrictas. Aún así, desde un punto de vista arquitectónico, el escenario que describes arriba debería incluso aparecer, ya que esto significa que estás enfrentando un olor de diseño de todos modos.