Solución:
Nos encontramos con un problema similar e ideamos varias posibles soluciones, pero no parece haber una solución elegante para lo que parece ser un problema común.
1) Prefijos. Data jpa ofrece varios prefijos (buscar, obtener, …) para un nombre de método. Una posibilidad es utilizar diferentes prefijos con diferentes gráficos con nombre. Este es el menor trabajo, pero oculta el significado del método al desarrollador y tiene un gran potencial para causar algunos problemas no obvios con la carga de las entidades incorrectas.
@Repository
@Transactional
public interface UserRepository extends CrudRepository<User, Integer>, UserRepositoryCustom {
@EntityGraph(value = "User.membershipYearsAndPreferences", type = EntityGraphType.LOAD)
User findByUserID(int id);
@EntityGraph(value = "User.membershipYears", type = EntityGraphType.LOAD)
User readByUserId(int id);
}
2) CustomRepository. Otra posible solución es crear métodos de consulta personalizados e inyectar EntityManager. Esta solución le brinda la interfaz más limpia para su repositorio porque puede nombrar sus métodos con algo significativo, pero es una cantidad significativa de complejidad para agregar a su código para proporcionar la solución Y está tomando manualmente el administrador de entidades en lugar de usar Spring Magic.
interface UserRepositoryCustom {
public User findUserWithMembershipYearsById(int id);
}
class UserRepositoryImpl implements UserRepositoryCustom {
@PersistenceContext
private EntityManager em;
@Override
public User findUserWithMembershipYearsById(int id) {
User result = null;
List<User> users = em.createQuery("SELECT u FROM users AS u WHERE u.id = :id", User.class)
.setParameter("id", id)
.setHint("javax.persistence.fetchgraph", em.getEntityGraph("User.membershipYears"))
.getResultList();
if(users.size() >= 0) {
result = users.get(0);
}
return result;
}
}
@Repository
@Transactional
public interface UserRepository extends CrudRepository<User, Integer>, UserRepositoryCustom {
@EntityGraph(value = "User.membershipYearsAndPreferences", type = EntityGraphType.LOAD)
User findByUserID(int id);
}
3) JPQL. Esencialmente, esto es simplemente renunciar a los gráficos de entidades con nombre y usar JPQL para manejar sus combinaciones por usted. No ideal en mi opinión.
@Repository
@Transactional
public interface UserRepository extends CrudRepository<User, Integer>, UserRepositoryCustom {
@EntityGraph(value = "User.membershipYearsAndPreferences", type = EntityGraphType.LOAD)
User findByUserID(int id);
@Query("SELECT u FROM users WHERE u.id=:id JOIN??????????????????????????")
User findUserWithTags(@Param("id") final int id);
}
Optamos por la opción 1 porque es la implementación más simple, pero esto significa que cuando usamos nuestros repositorios tenemos que mirar los métodos de recuperación para asegurarnos de que estamos usando el que tiene el gráfico de entidad correcto. Buena suerte.
Fuentes:
- JPA EntityGraph con diferentes vistas usando Spring
- https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods
No tengo suficiente reputación para publicar todas mis fuentes. Perdón 🙁
Tuvimos el mismo problema y creamos una extensión Spring Data JPA para resolverlo:
https://github.com/Cosium/spring-data-jpa-entity-graph
Esta extensión permite pasar EntityGraph con nombre o construido dinámicamente como un argumento de cualquier método de repositorio.
Con esta extensión, tendría este método disponible de inmediato:
List<Complaint> findAll(Sort sort, EntityGraph entityGraph);
Y poder llamarlo con un EntityGraph seleccionado en tiempo de ejecución.
Usar @EntityGraph
Juntos con @Query
@Repository
public interface ComplaintRepository extends JpaRepository<Complaint, Long>{
@EntityGraph(value = "allJoinsButMessages" , type=EntityGraphType.FETCH)
@Query("SELECT c FROM Complaint ORDER BY ..")
@Override
List<Complaint> findAllJoinsButMessages();
@EntityGraph(value = "allJoins" , type=EntityGraphType.FETCH)
@Query("SELECT c FROM Complaint ORDER BY ..")
@Override
List<Complaint> findAllJoin();
...
}