Search code examples
javahibernatemany-to-manyspring-data-jpa

N+1 query on bidirectional many to many for same entity type


I have an entity as below. I want to get an entity from DB with all of her/his friends with their primitive type fields (id, name). In this example, it is trying to return all friends and the friends of the friends so it is creating an infinite loop. I just want to get the first level friend objects with primitive fields. It seems like a N+1 query problem but I could not find a solution for it. Is there any solution for stopping this infinite recursion and returning the response as I mentioned?

@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "PERSON")
@ToString(exclude = "friends")
@EqualsAndHashCode(exclude = "friends")
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @Column(name = "name",unique = true)
    private String name;

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "FRIENDSHIP",
           joinColumns = @JoinColumn(name = "person_id",  referencedColumnName = "id"),
           inverseJoinColumns = @JoinColumn(name = "friend_id",  referencedColumnName = "id"))
    private Set<Person> friends;

I am creating the bidirectional friendship as below:

public Person makeFriendship(String personName, String friendName) 
    throws FriendshipExistsException, PersonNotFoundException {
    Person person = retrieveWithName(personName);
    Person friend = retrieveWithName(friendName);
    if(!person.getFriends().contains(friend)){
        person.getFriends().add(friend);
        friend.getFriends().add(person);
        return repository.save(person);
} else {
    throw new FriendshipExistsException(personName, friendName);
}

It is giving the following error:

Could not write JSON: Infinite recursion (StackOverflowError);

But I think the root cause is N+1 query but neither @EntityGraph nor @JsonBackReference became a solution for my case. I am not sure how to implement them for same type entity relationships.

PS: I have a premise question about same code: Many to many relationship for same type entity


Solution

  • Try to use:

    @JsonIgnoreProperties("friends")
    private Set<Person> friends;
    

    It should prevent friends from the displaying of their friends in recursion.