ВЫБОРКА ЛЕВОГО СОЕДИНЕНИЯ не решает проблему n 1

#mysql #hibernate #jpa #spring-data-jpa #select-n-plus-1

Вопрос:

Я хотел бы спросить о решении проблемы N 1. У меня есть таблица учетных записей и таблица учетных записей с отношениями 1:M. Я пробую метод выборки соединения, используя ВЫБОРКУ ЛЕВОГО СОЕДИНЕНИЯ в @Query, но он не работает.

Класс учетной записи:

 @Entity(name = "account")
@Table(name = "account")
public class AccountBean implements Serializable {
    @Id
    @Column("username")
    private String username

    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name = "username", referencedColumnName = "username", insertable = false, updatable = false)
    private Set<AccountRoleBean> roles = new HashSet<>();

    // getters setters
}
 

Класс ролей учетной записи:

 @Entity(name = "account_role")
@Table(name = "account_role")
public class AccountRoleBean implements Serializable {

    @Id
    @Column(name = "id")
    private Integer id;

    @Column(name = "username")
    private String username;

    // getters setters
}
 

Класс хранилища учетных записей

 public interface AccountRepo extends JpaRepository<AccountBean, String> {
    @Query("FROM account a LEFT JOIN FETCH account_role role ON a.username = role.username WHERE a.username = :username")
    AccountBean findAccountWithRoles(String username);
}
 

Выход

 Hibernate: 
    select
        accountbea0_.username as username1_0_0_,
        accountrol1_.id as id1_1_1_,
        accountbea0_.is_active as is_activ2_0_0_,
        accountbea0_.last_login_date as last_log3_0_0_,
        accountbea0_.pw as pw4_0_0_,
        accountrol1_.username as username3_1_1_,
        accountrol1_.role_name as role_nam2_1_1_ 
    from
        account accountbea0_ 
    left outer join
        account_role accountrol1_ 
            on (
                accountbea0_.username=accountrol1_.username
            ) 
    where
        accountbea0_.username=?
Hibernate: 
    select
        roles0_.username as username3_1_0_,
        roles0_.id as id1_1_0_,
        roles0_.id as id1_1_1_,
        roles0_.username as username3_1_1_,
        roles0_.role_name as role_nam2_1_1_ 
    from
        account_role roles0_ 
    where
        roles0_.username=?
 

Ответ №1:

Используя JPQL, вам не нужно указывать объединяющую таблицу и столбцы для объединения, потому что вы уже сделали это в своих сущностях.

Ваш запрос должен быть таким:

 @Query("FROM account a LEFT JOIN FETCH a.roles r WHERE a.username = :username")
 

Ответ №2:

Лучшим решением является использование графов сущностей имен. Графики сущностей определяют, какие поля следует охотно извлекать, и вы можете повторно использовать один и тот же график для нескольких запросов, даже для запросов, автоматически выводимых данными Spring из имен методов репозитория. Вы можете определить график именованной сущности поверх вашей AccountBean сущности, где вы бы указали @NamedAttributeNode("roles") , так как вы хотите, чтобы она была извлечена с нетерпением. Тогда вы сделали бы что-то вроде

accountRepo.findByName(myName, EntityGraph.EntityGraphType.LOAD, "theNameOfYourCustomEntityGraph");