create - Spring Data JPA y NamedEntityGraphs
create entity graph (4)
¿Puede intentar crear el nombre EntiyGraph con el elemento secundario que solicitará y asignar el mismo nombre al método find all? Ex:
@EntityGraph(value = "fetch.Profile.Address.record", type = EntityGraphType.LOAD)
Employee getProfileAddressRecordById(long id);
Para su caso:
@NamedEntityGraph(name="all.Customer.handling_employee.genre", attributeNodes = {
@NamedAttributeNode("customer"),
@NamedAttributeNode("handling_employee"),
@NamedAttributeNode("genre")
})
nombre del método en el repositorio
@EntityGraph(value = "all.Customer.handling_employee.genre" , type=EntityGraphType.FETCH)
findAllCustomerHandlingEmployeeGenre
De esta manera puede realizar un seguimiento de los diferentes métodos findAll.
Actualmente estoy luchando para poder obtener solo los datos que necesito. El método findAll () necesita obtener datos dependiendo de dónde se llama. No quiero terminar escribiendo diferentes métodos para cada gráfico de entidad. Además, evitaría llamar a los gestores de entidades y formar las consultas (repetitivas) yo mismo. Básicamente quiero usar la compilación en el método findAll, pero con el gráfico de entidades de mi agrado. ¿Cualquier oportunidad?
@Entity
@Table(name="complaints")
@NamedEntityGraphs({
@NamedEntityGraph(name="allJoinsButMessages", attributeNodes = {
@NamedAttributeNode("customer"),
@NamedAttributeNode("handling_employee"),
@NamedAttributeNode("genre")
}),
@NamedEntityGraph(name="allJoins", attributeNodes = {
@NamedAttributeNode("customer"),
@NamedAttributeNode("handling_employee"),
@NamedAttributeNode("genre"),
@NamedAttributeNode("complaintMessages")
}),
@NamedEntityGraph(name="noJoins", attributeNodes = {
})
})
public class Complaint implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private long id;
private Timestamp date;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "customer")
private User customer;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "handling_employee")
private User handling_employee;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="genre")
private Genre genre;
private boolean closed;
@OneToMany(mappedBy = "complaint", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<ComplaintMessage> complaintMessages = new ArrayList<ComplaintMessage>();
//getters and setters
}
Y mi JPARepository
@Repository
public interface ComplaintRepository extends JpaRepository<Complaint, Long>{
List<Complaint> findByClosed(boolean closed);
@EntityGraph(value = "allJoinsButMessages" , type=EntityGraphType.FETCH)
@Override
List<Complaint> findAll(Sort sort);
}
Nos encontramos con un problema similar e ideamos varias soluciones posibles, pero no parece haber una solución elegante para lo que parece ser un problema común.
1) Prefijos Data jpa proporciona varios prefijos (find, get, ...) para un nombre de método. Una posibilidad es usar diferentes prefijos con diferentes gráficos con nombre. Este es el trabajo mínimo, pero oculta el significado del método del desarrollador y tiene un gran potencial para causar algunos problemas no obvios con la carga de 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 el EntityManager. Esta solución le brinda la interfaz más limpia para su repositorio porque puede nombrar a sus métodos como algo significativo, pero es una cantidad significativa de complejidad agregar a su código para proporcionar la solución Y está agarrando manualmente el administrador de la entidad 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 uniones 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);
}
Elegimos 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. Lo siento :(
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 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.
Use
@EntityGraph
junto 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();
...
}