Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data JPA And NamedEntityGraphs

currently I am wrestling with being able to fetch only the data I need. The findAll() method needs to fetch data dependant on where its getting called. I do not want to end up writing different methods for each entity graph. Also, I would avoid calling entitymanagers and forming the (repetitive) queries myself. Basicly I want to use the build in findAll method, but with the entity graph of my liking. Any chance?

@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 } 

And my 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); } 
like image 492
dendimiiii Avatar asked Aug 11 '15 14:08

dendimiiii


People also ask

What is the difference between spring JPA and Spring Data JPA?

Spring Data JPA is a JPA data access abstraction. Just like JPA, Spring Data JPA cannot work without a JPA provider. Spring Data JPA offers a solution to the DDD Repository pattern or the DAO (Data Acess Object) pattern . It can also generate JPA queries on your behalf through method name conventions.

What is the use of NamedEntityGraph?

NamedEntityGraph annotation defines a single named entity graph and is applied at the class level. Multiple @NamedEntityGraph annotations may be defined for a class by adding them within a javax. persistence. NamedEntityGraphs class-level annotation.

What is Spring Data JPA and advantages over ORM?

Conclusion. Hibernate is a JPA provider and ORM that maps Java objects to relational database tables. Spring Data JPA is an abstraction that makes working with the JPA provider less verbose. Using Spring Data JPA you can eliminate a lot of the boilerplate code involved in managing a JPA provider like Hibernate.

Is Spring Data JPA and ORM?

No. It is a system to create "automatic" Data Access Objects (DAOs) for you at compile time, and uses an ORM (like Hibernate) in these DAOs.


1 Answers

We ran into a similar problem and devised several prospective solutions but there doesn't seem to be an elegant solution for what seems to be a common problem.

1) Prefixes. Data jpa affords several prefixes (find, get, ...) for a method name. One possibility is to use different prefixes with different named graphs. This is the least work but hides the meaning of the method from the developer and has a great deal of potential to cause some non-obvious problems with the wrong entities loading.

@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. Another possible solutions is to create custom query methods and inject the EntityManager. This solution gives you the cleanest interface to your repository because you can name your methods something meaningful, but it is a significant amount of complexity to add to your code to provide the solution AND you are manually grabbing the entity manager instead of using 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. Essentially this is just giving up on named entity graphs and using JPQL to handle your joins for you. Non-ideal in my opinion.

@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); } 

We went with option 1 because it is the simplest in implementation but this does mean when we use our repositories we have have to look at the fetch methods to make sure we are using the one with the correct entity graph. Good luck.

Sources:

  • JPA EntityGraph with different views using Spring
  • https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods

I don't have enough reputation to post all of my sources. Sorry :(

like image 165
Chris Spencer Avatar answered Oct 06 '22 14:10

Chris Spencer