2 votes

Spring Data JPA charge une relation one to one en deux requêtes

J'ai les classes suivantes :

@Data
@Entity
@Table(name = "user_info")
public class UserIdentity implements UserDetails {
  @Id
  private Long id;
  private String username;
  private String password;
  private String facebookId;
  private String phoneNumber;
  private Timestamp unblockDate;
  @OneToOne(fetch = FetchType.EAGER, optional = false)
  @Fetch(FetchMode.JOIN)
  @JoinColumn(name = "role_id")
  private Role role;

  }

@Data
@Entity
@Table(name = "role")
public class Role {
  @Id
  private Long id;
  private String name;
  @ManyToMany
  @Fetch(FetchMode.JOIN)
  @JoinTable(name = "role_permission", joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "permission_id", referencedColumnName = "id"))
  private List<Permission> permissions;
}

@Data
@Entity
@Table(name = "permission")
public class Permission {
  @Id
  private Long id;
  private String name;
}

Et lorsque j'interroge l'identité de l'utilisateur, je vois ces deux requêtes générées dans le journal :

Hibernate: select useridenti0_.id as id1_3_, useridenti0_.facebook_id as facebook2_3_, useridenti0_.password as password3_3_, useridenti0_.phone_number as phone_nu4_3_, useridenti0_.role_id as role_id7_3_, useridenti0_.unblock_date as unblock_5_3_, useridenti0_.username as username6_3_ from user_info useridenti0_ where useridenti0_.facebook_id=?
Hibernate: select role0_.id as id1_1_0_, role0_.name as name2_1_0_, permission1_.role_id as role_id1_2_1_, permission2_.id as permissi2_2_1_, permission2_.id as id1_0_2_, permission2_.name as name2_0_2_ from role role0_ left outer join role_permission permission1_ on role0_.id=permission1_.role_id left outer join permission permission2_ on permission1_.permission_id=permission2_.id where role0_.id=?

Mais je m'attends à ce qu'il n'y ait qu'une seule requête. Pouvez-vous m'aider à trouver ce que je fais de travers ?

MISE À JOUR J'utilise CrudRepositor :

public interface UserIdentityRepository extends CrudRepository<UserIdentity, Long> {
  UserIdentity findByFacebookId(String facebookId);
  UserIdentity findByPhoneNumber(String phoneNumber);
}

J'ai remarqué la chose suivante : si j'effectue une recherche à l'aide de la méthode findById() cela fonctionne comme prévu, mais si j'utilise findByPhoneNumber() il ne fonctionne pas.

4voto

Jens Schauder Points 23468

Les FetchType que vous spécifiez sur vos entités n'est utilisée que lors de l'utilisation des méthodes de la classe EntityManager qui n'acceptent aucune demande de renseignements. C'est ce que vous faites en réalité lorsque vous appelez findById() .

Mais si vous spécifiez une requête comme Spring Data le fait pour vous lorsque vous utilisez une méthode de requête comme findByPhoneNumber() cette requête est utilisée pour déterminer la stratégie de recherche.

Mais vous pouvez contrôler cela en spécifiant un graphe d'entités. Vous pouvez ajouter un @NamedEntityGraph à votre classe d'entité. Et une annotation @EntityGraph à votre méthode de requête faisant référence à ce graphe d'entités nommées.

J'ai préparé un exemple simple sur Github

J'ai utilisé le graphe d'entités trivial

@NamedEntityGraph(name = "joined", includeAllAttributes = true)

Il récupère tout avec empressement, ce qui est peut-être ce que vous voulez.

0voto

Maciej Kowalski Points 12727

La seule façon d'avoir une seule requête et elle ne chargerait que le fichier UserIdentity dans votre cas, est de définir la relation comme paresseuse :

@OneToOne(fetch = FetchType.LAZY, optional = false)
@Fetch(FetchMode.JOIN)
@JoinColumn(name = "role_id")
private Role role;

puis le charger lors de sa première utilisation dans une méthode transactionnelle.

Si cela correspond à votre conception logique, vous pouvez faire de Role.id une clé primaire ainsi qu'une clé étrangère et utiliser @MapsId comme décrit dans cet article : lien

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X