2017-08-07 1 views
1

J'écris une API à l'aide de Spring Boot et Hibernate où mes objets entité persistants sont également utilisés comme DTO envoyés vers et depuis le client. Ceci est une version simplifiée d'une entité typique que j'utilise:Obtenir les ID d'une table de mappage ManyToMany

@Entity 
@Table(name = "STUDENT") 
public class Student { 
    @Id 
    @GeneratedValue 
    @Column(name = "ID") 
    private Long id; 

    @ElementCollection 
    @CollectionTable(name = "GROUP_STUDENT", 
        joinColumns = @JoinColumn(name = "GROUP_ID")) 
    @Column(name="STUDENT_ID") 
    private Set<Long> groupIds; 

    @JsonIgnore 
    @ManyToMany(fetch = FetchType.LAZY) 
    @JoinTable(name="GROUP_STUDENT", 
       joinColumns = @JoinColumn(name="GROUP_ID"), 
       inverseJoinColumns = @JoinColumn(name="STUDENT_ID") 
    ) 
    private Set<Group> groups = new HashSet<>(); 

    // getters and setters 
} 

et c'est la classe associée:

@Entity 
@Table(name = "GROUP") 
public class Group { 
    @Id 
    @GeneratedValue 
    @Column(name = "ID") 
    private Long id; 

    @JsonIgnore 
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "groups") 
    private Set<Student> students = new HashSet<>(); 

    // getters and setters 
} 

Comme vous pouvez le voir, il y a une association entre @ManyToManyStudent et Group.

Depuis que j'envoie des objets comme ceux-ci au client, je choisis d'envoyer seulement les id des associations et pas les associations elles-mêmes. J'ai résolu ceci en utilisant this answer et cela fonctionne comme prévu.

Le problème est le suivant. Lorsque Hibernate tente de conserver un objet Student, il insère le groups comme prévu, mais il essaie également d'insérer le groupIds dans la table de mappage GROUP_STUDENT. Cela échouera bien sûr à cause de la contrainte unique de l'identifiant composite de la table de mappage. Et il n'est pas possible de marquer groupIds comme insertable = false puisqu'il s'agit d'un @ElementCollection. Et je ne pense pas que je peux utiliser @Formula puisque j'ai besoin d'un Set et non d'une valeur réduite. Ceci peut bien sûr être résolu en vidant toujours groups du groupIds avant d'enregistrer ou de conserver une telle entité, mais cela est extrêmement risqué et facile à oublier.

Donc ce que je veux est fondamentalement un groupIds en lecture seule dans la classe Student qui charge les données de la table de mappage GROUP_STUDENT. Est-ce possible? Je suis reconnaissant pour toutes les suggestions et heureux de travailler sur la question si cela ne semble pas clair.

Répondre

1

J'ai réussi à résoudre ce problème en faisant l'ID de collecte @Transient et peuplant utilisant @PostLoad:

@Entity 
@Table(name = "STUDENT") 
public class Student { 
    @PostLoad 
    private void postLoad() { 
     groupIds = groups.stream().map(Group::getId).collect(Collectors.toSet()); 
    } 

    @Id 
    @GeneratedValue 
    @Column(name = "ID") 
    private Long id; 

    @Transient 
    private Set<Long> groupIds; 

    @JsonIgnore 
    @ManyToMany(fetch = FetchType.LAZY) 
    @JoinTable(name="GROUP_STUDENT", 
       joinColumns = @JoinColumn(name="GROUP_ID"), 
       inverseJoinColumns = @JoinColumn(name="STUDENT_ID") 
    ) 
    private Set<Group> groups = new HashSet<>(); 

    // getters and setters 
}