#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");