2

I have defined the JPA Entity Graph on my Entity class, and it looks like follows.

UserTable.java

@Entity
@Table(name = "USER")
@NamedEntityGraph(
        name = "user-entity-graph-with-photos", 
        attributeNodes = {
                @NamedAttributeNode(value = "photos"),
        })
public class UserTable {

    @Id
    @Column(name = "USER_ID", nullable = false)
    private Long userId;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    private Set<PhotoTable> photos = new HashSet<>();

The requirement is that sometimes I want to fetch the users along with the photos, and in some other cases I only want the users to be loaded from the database, but not the photos.

Now, I have created a DAO class for the User - UserDAO.java. In there, I have two methods, each for one case.

public Optional<UserTable> findByEmail(String email) {
    final TypedQuery<UserTable> query = entityManager.createQuery(
            "SELECT e FROM UserTable e WHERE e.email = :email", UserTable.class);

    return Optional.ofNullable(query.setParameter("email", email).getSingleResult());
}

public Optional<UserTable> findByEmailWithPhotos(String email) {
    final TypedQuery<UserTable> query = entityManager.createQuery(
            "SELECT e FROM UserTable e WHERE e.email = :email", UserTable.class);

    return Optional.ofNullable(query
            .setParameter("email", email)
            .setHint("javax.persistence.loadgraph", entityManager.getEntityGraph("user-entity-graph-with-photos"))
            .getSingleResult());
}

I am a bit worried about the API in the DAO layer, since it now contains 2 methods like findByEmail and findByEmailWithPhotos which also loads the photos eagerly. Is this the correct approach? Should we really use one DAO method for each defined entity graph? Would some kind of a builder pattern be more effective here? Any advice is appreciated.

UPDATE

To explain further what I feel is bad about this design is the following. Let's suppose we have 3 entity graphs on the user

  1. user-graph-with-photos
  2. user-graph-with-messages
  3. user-graph-with-followers

Then in the DAO would need to have the following methods:

  1. findUsers
  2. findUsersWithPhotos
  3. findUsersWithMessages
  4. findUsersWithFollowers
  5. findUsersWithPhotosAndMessages
  6. findUsersWithPhotosAndFollowers
  7. findUsersWithMessagesAndFollowers
  8. findUsersWithPhotosAndMessagesAndFollowers
wesleyy
  • 2,575
  • 9
  • 34
  • 54
  • How would your proposed builder pattern work? How would it improve on your current solution? And what about your current solution is it that you feel _needs_ improvement? – Kevin Anderson Jan 26 '19 at 09:24
  • @KevinAnderson I feel that those are the same queries, only decorated with another "filter", so I think having two separated method that basically do the same, just the other one has some upgrade is not a good design. A builder could possibly be like Set users = DAO.queryBuilder().findUsers().withPhotos().query(); – wesleyy Jan 26 '19 at 09:49
  • @KevinAnderson Please see my update – wesleyy Jan 26 '19 at 09:56
  • I'd suggest that instead of `findByEmail` and `findByEmailWithPhotos`, you probably should go initially with `findByEmail` and `findByEmailWithAllDetails`. Add specific methods that eager-fetch particular combinations of attributes when (and only _if_) it makes sense, but don't feel that you automatically _have to_ anticipate and cater to eager loading any-and-every possible combination of collection attributes from the get-go – Kevin Anderson Jan 27 '19 at 03:38

0 Answers0