Skip to content

Redundant JOIN Generated with @EntityGraph in Spring Data JPA Query Methods #3717

@amiriahmad72

Description

@amiriahmad72

Issue: Redundant JOIN Generated with @EntityGraph in Spring Data JPA Query Methods

When using @EntityGraph in a repository method that relies on query generation by method name (without explicitly defining a query using @Query or @NamedQuery), redundant JOIN statements are generated if the method name references a relationship that is also included in the attributePaths of @EntityGraph.

Environment:

  • Java 21
  • Spring Boot 3.4.0 (Spring Data 3.4.0)

Steps to Reproduce:

You can reproduce this issue using this sample project. The project includes two test cases, one of which fails due to the issue.

I captured the generated SQL statements using a Hibernate interceptor and verified the occurrence count of JOIN operations.

Entities:

Here are the entity definitions:

@Setter
@Getter
@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Nationalized
    @Column(length = 255, unique = true, nullable = false)
    private String name;

    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private Company company;

}
@Setter
@Getter
@Entity
public class Company {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Nationalized
    @Column(length = 255, unique = true, nullable = false)
    private String name;

    private boolean enable;

}

Repository Methods:

The EmployeeRepository contains the following two methods:

public interface EmployeeRepository extends JpaRepository<Employee, Long> {

    @EntityGraph(attributePaths = "company")
    Set<Employee> findAllByCompanyEnableIsTrue();

    @EntityGraph(attributePaths = "company")
    @Query("""
            SELECT e
            FROM Employee e
            WHERE e.company.enable
            """)
    Set<Employee> findAllByCompanyEnableIsTrueUsingQuery();

}

Generated SQL Queries:

For the first method (findAllByCompanyEnableIsTrue), which relies on the method name for query generation, the following SQL is generated:

select
    e1_0.id,
    e1_0.company_id,
    c2_0.id,
    c2_0.enable,
    c2_0.name,
    e1_0.name
from employee e1_0
join company c1_0 on c1_0.id = e1_0.company_id
join company c2_0 on c2_0.id = e1_0.company_id
where c1_0.enable

As shown, there is a redundant JOIN.

However, for the second method (findAllByCompanyEnableIsTrueUsingQuery), which uses an explicitly defined query, the generated SQL is:

select
    e1_0.id,
    e1_0.company_id,
    c1_0.id,
    c1_0.enable,
    c1_0.name,
    e1_0.name
from employee e1_0
join company c1_0 on c1_0.id = e1_0.company_id
where c1_0.enable

This query avoids the redundant JOIN.

Expected Behavior:

The query generated for the method using the method name (findAllByCompanyEnableIsTrue) should avoid redundant JOIN statements, similar to the query generated by findAllByCompanyEnableIsTrueUsingQuery.

Observed Behavior:

Using @EntityGraph with query methods generated by method name causes redundant JOIN operations when a relationship is referenced in both the method name and the attributePaths of @EntityGraph.

Additional Information:

Please let me know if further clarification or additional examples are needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions