Search code examples
spring-bootjpaspring-data-jpa

JPA nested object LAZY FETCH returns only first object


I have the following.

@Data
@Getter
@Setter
@Accessors(fluent = false, chain = true)
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@MappedSuperclass
@Slf4j
class Base {
  private Timestamp createdTime;
  private Timestamp modifiedTime;
  private String createdBy;
  private String modifiedBy;
  private Boolean deleted = false;
}

@Getter
@Setter
@Builder
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "account")
@SQLDelete(sql = "UPDATE account SET deleted = true WHERE account_id = ?")
@Where(clause = "deleted=false")
class Account {
  @Id
  @EqualsAndHashCode.Include()
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long accountId;

  @Builder.Default
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "account", cascade = {CascadeType.ALL})
  private Set<Collab> collaborators = new HashSet<>(0);
  private String objId;
}

class Collab {
  @Id
  @EqualsAndHashCode.Include()
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long collabId;
  private String email;
  private String role;
  @JsonBackReference
  @JoinColumn(name = "accountId")
  @ManyToOne(fetch = FetchType.EAGER)
  private Account account;
}

public interface AccountRepo {
  Optional<Account> findByObjId(String objId);
}

Even though there are multiple collab for a single account in the DB. When I inspect the response of AccountRepo.findByObjId (or findAll) method, only 1 element is inside collaborators for any account object. What am I missing?

PS: @EqualsAndHashCode.Include() is from lombok


Solution

  • When you inspect the response of AccountRepo.findByObjId or findAll, you may only see one element inside the collaborators set because the lazy-loading mechanism loads the related Collab entities on-demand. If you access the collaborators set after retrieving an Account object, it should trigger the loading of the associated Collab entities from the database.

    Try by implementing a getter method for collaborators like this

    public Set<Collab> getCollaborators() {
      return collaborators;
    }
    

    after that you can access the collaborators like this

    Optional<Account> accountOptional = accountRepo.findByObjId(objId);
    if (accountOptional.isPresent()) {
      Account account = accountOptional.get();
      Set<Collab> collaborators = account.getCollaborators(); // Load collaborators
    }