Datos De Primavera JPA Y NamedEntityGraphs


Actualmente estoy luchando con ser capaz de obtener solo los datos que necesito. El método findAll () necesita obtener datos dependiendo de dónde se llame. No quiero terminar escribiendo diferentes métodos para cada gráfico de entidad. Además, evitaría llamar a entitymanagers y formar las consultas (repetitivas) yo mismo. Básicamente quiero usar el método build in findAll, pero con el gráfico de entidades de mi agrado. ¿Alguna posibilidad?

@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);
}
Author: dendimiiii, 2015-08-11

4 answers

Nos encontramos con un problema similar e ideamos varias soluciones prospectivas, pero no parece haber una solución elegante para lo que parece ser un problema común.

1) Prefijos. Data jpa ofrece varios prefijos (find, get,...) para un nombre de método. Una posibilidad es usar diferentes prefijos con diferentes grafos con nombre. Este es el que menos trabajo, pero oculta el significado del método del desarrollador y tiene un gran potencial para causar algunos problemas obvios con el mal entidades cargando.

@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 solución posible es crear métodos de consulta personalizados e inyectar el EntityManager. Esta solución le da la interfaz más limpia a su repositorio porque puede nombrar sus métodos algo significativo, pero es una cantidad significativa de complejidad para agregar a su código para proporcionar la solución Y está agarrando manualmente el entity manager 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 solo dar up on named entity graphs and using JPQL to handle your joins for you. No es 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 más simple en la implementación, pero esto significa que cuando usamos nuestros repositorios tenemos que mirar los métodos fetch para asegurarnos de que estamos utilizando el que tiene el entity graph correcto. Buena suerte.

Fuentes:

No tengo suficiente reputación para publicar todas mis fuentes. Lo sentimos: (

 28
Author: Chris Spencer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:25:57

Usar @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();

   ...

}

 11
Author: GKislin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-17 10:40:10

Tuvimos el mismo problema y construimos 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, usted tendría este método inmediatamente disponible:

List<Complaint> findAll(Sort sort, EntityGraph entityGraph);

Y poder llamarlo con un EntityGraph seleccionado en tiempo de ejecución.

 10
Author: Réda Housni Alaoui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-26 18:54:26

Puede intentar crear el nombre de EntiyGraph con el hijo que va a solicitar y dar 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.

 1
Author: smile,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-09 20:40:36