Skip to content

@EntityGraph is affected by where in many to many relation #2543

Open
@joejoe2

Description

@joejoe2

If we define two entities with many to many relation

@Data
@Entity
@Table(name = "groups")
public class Group {
    @Id
    @GeneratedValue
    @Column(unique = true, updatable = false, nullable = false)
    Integer id;

    @ManyToMany
    Set<User> members;
}
@Data
@Entity
@Table(name = "account_user")
public class User {
    @Id
    @GeneratedValue
    @Column(unique = true, updatable = false, nullable = false)
    Integer id;

    @Column(updatable = false, nullable = false)
    String name;
}

In order to avoid n+1 problem when querying the groups containing some user, we usually use @EntityGraph or join fetch in jpql like belows:

@Repository
public interface GroupRepository extends JpaRepository<Group, Integer> {
    List<Group> findAll();

    @EntityGraph(attributePaths = {"members"})
    List<Group> findByMembers(User user);

    @Query("select distinct g from Group g join fetch g.members where :user member g.members")
    List<Group> findByMembersWithJoinFetch(@Param("user") User user);
}

The join fetch will return desired groups with their all members in one select statement, but the method of @EntityGraph will return the groups with only one members based on the query parameter (it does not retrieve all members in that group !)

I write the below test to reproduce this problem with spring-data-jpa:2.7.0, you can find the test program in attachment

@SpringBootTest
class GroupRepositoryTest {
    @Autowired
    UserRepository userRepository;
    @Autowired
    GroupRepository groupRepository;

    User userA, userB, userC;

    @BeforeEach
    void setUp() {
        userA = new User();
        userA.setName("a");
        userB = new User();
        userB.setName("b");
        userC = new User();
        userC.setName("c");
        userRepository.saveAll(Arrays.asList(userA, userB, userC));
    }

    @Test
    void findByMembersIn() {
        //create group
        Group group = new Group();
        group.setMembers(new HashSet<>(Arrays.asList(userA, userB, userC)));
        groupRepository.save(group);
        //test
        //pass
        assertEquals(group.getMembers(), groupRepository.findByMembersWithJoinFetch(userA).get(0).getMembers());
        //fail
        assertEquals(group.getMembers(), groupRepository.findByMembers(userA).get(0).getMembers());
    }
}

I am wondering that is this working as designed or the @EntityGraph should not have this behavior ?
jpa-join-demo.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions