2 votes

Comment configurer une entité enfant référençant le parent par son seul ID en utilisant une JoinTable dans Spring JPA/Hibernate ?

Problème

  1. J'ai une entité parent avec une relation un-à-plusieurs avec l'entité entités enfants.
  2. Mapstruct est utilisé pour mapper les entités aux DTOs, donc simplement récupérer tout (même paresseusement) résultera en l'instanciation/la récupération de chaque instance à partir de la persistance (ce que nous ne voulons pas, je ne me soucie que des IDs en dehors des classes Spring JPA/Hibernate).
  3. Les tables du parent et de l'enfant n'ont aucune référence l'une de l'autre, la relation est gérée par une table de jonction.

Je ne m'intéresse qu'aux identifiants des associations. Je ne veux pas que la DTO ait la classe associée respective comme attribut. Je veux Parent d'avoir Set<String> childIds y Child d'avoir String parentId dans les DTO. Pour cette raison, je ne veux pas charger l'objet entier dans la couche de persistance juste pour faire disparaître tout le reste.

Tentatives

  1. Faire en sorte que les classes d'entités fassent référence à l'autre classe d'entité. Le DTO de l'entité est ok mais l'entité DTO Entity Hibernate/Spring JPA se plaint que l'entité est détachée (parce qu'elle vient de provenir d'un ID). Une solution à laquelle j'ai pensé est d'appeler EntityManager.getReference mais cela provoque une erreur s'il s'agit d'une nouvelle entité, alors comment puis-je en enregistrer de nouvelles ? Je devrais faire un existsById mais maintenant nous faisons encore plus d'appels à la base de données, ça devient cher.
  2. Un tas de combinaisons de JoinColumn , JoinColumns , JoinTable etc.

Classes Java

Entités

@Entity
@(LombokGettersAndSetters)
public class ParentEntity {

    @Id
    private Long id;

    @(???)
    private Set<Long> childIds; || private Set<ChildEntity> children;
}

@Entity
@(LombokGettersAndSetters)
public class ChildEntity {

    @Id
    private Long id;

    @(???)
    private Long parentId; || private ParentEntity parent;
}

Mappers

(Mapstruct mappers)

DTOs

public class ParentDTO {
    private Long id;
    private Set<Long> childIds;
}

public class ChildDTO {
    private Long id;
    private Long parentId;
}

Tableaux

Parent       Child      Parent_join_Child
-------      -----      -----------------
id           id         parent_id
                        child_id

Merci d'avance !

Editer @ +1m : Je dois noter que j'ai supprimé certaines annotations dans mes exemples tels que ceux ci-dessous.

@Column(name = "parent_id", columnDefinition = CustomColumnDefinition.UNSIGNED_INT)
@GeneratedValue(strategy = GenerationType.IDENTITY)

2voto

SSK Points 2328

Vous pouvez utiliser @JoinTable pour joindre votre parent à l'enfant comme indiqué ci-dessous

@Entity
@(LombokGettersAndSetters)
public class ParentEntity {

    @Id
    private Long id;

    @JoinTable(name = "Parent_join_Child", joinColumns = {
            @JoinColumn(name = "parent_id", referencedColumnName = "id") }, inverseJoinColumns = {
                    @JoinColumn(name = "child_id", referencedColumnName = "id") })
    private Set<ChildEntity> children;
}

0voto

ivan Points 55

Pouvez-vous faire ce qui suit :

Créer l'entité ParentChild :

@Entity
public class ParentChild {

  private long id;
  private long parentId;
  private long childId;

}

et de travailler avec elle :

   parentChildRepository.findByWhatever() and group by parent and map to dto.

0voto

Christian Beikov Points 223

Il vous faudrait écrire une requête personnalisée qui ne sélectionnerait que les parties qui vous intéressent, mais vous ne pourriez alors pas utiliser Mapstruct. Je vous recommande de jeter un coup d'œil à ce que Vues d'entités de Blaze-Persistence a à offrir.

J'ai créé la bibliothèque pour permettre un mappage facile entre les modèles JPA et les modèles définis par une interface personnalisée ou une classe abstraite, un peu comme les projections de données de Spring sur les stéroïdes. L'idée est de définir votre structure cible (modèle de domaine) comme vous le souhaitez et de mapper les attributs (getters) via des expressions JPQL vers le modèle d'entité.

En supposant un modèle d'entité comme celui-ci :

@Entity
public class ParentEntity {

    @Id
    private Long id;

    @OneToMany(mappedBy = "parent")
    private Set<ChildEntity> children;
}

@Entity
public class ChildEntity {

    @Id
    private Long id;

    @ManyToOne
    private ParentEntity parent;
}

Un modèle DTO pour votre cas d'utilisation pourrait ressembler à ce qui suit avec les vues d'entités de Blaze-Persistence :

@EntityView(ParentEntity.class)
public interface ParentDTO {
    @IdMapping
    Long getId();
    @Mapping("children.id")
    Set<Long> getChildIds();
}

L'interrogation consiste à appliquer la vue d'entité à une requête, la plus simple étant simplement une requête par id.

ParentDTO a = entityViewManager.find(entityManager, ParentDTO.class, id);

Dans les coulisses, la requête sera créée pour récupérer exactement ce qui est nécessaire, rien de plus.

L'intégration de Spring Data vous permet de l'utiliser presque comme Spring Data Projections : https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

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