Bonjour
Je débute en JPA / Hibernate par un schéma multi-tenant.
J'ai une base de données simplifiée comme ceci:
- studies: tenant_id, study_id sont des cléfs privées
- physicians: tenant_id, physician_id sont des cléfs privées
- les 2 sont liées par une table studies_ord_phys:
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 CREATE TABLE registry.studies_ord_phys ( tenant_id uuid NOT NULL, study_id uuid NOT NULL, physician_id uuid NOT NULL, CONSTRAINT pk PRIMARY KEY (tenant_id, study_id, physician_id) );
où un examen ('study') peut avoir plusieurs médecins demandeurs ('ordering physician'), et un médecin demander plusieurs examens.
Je n'ai pas besoin de lien bidirectionnel entre les examens et les médecins, et je n'en veux d'ailleurs pas parce que les examens ont également des 'médecins destinataires' qui pointent aussi vers la même table 'physicians'.
Je ne trouve pas de moyen de lier correctement les physicians avec les studies.
En Java, j'ai créé un ID 'embeddable' pour mes examens:
Pareil pour le PhysicianId (qui contient aussi le tenantId et son id)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 @Embeddable public class StudiesId implements Serializable { @Column(name = "tenant_id", nullable = false) private UUID tenantId; @Column(name = "id", nullable = false) private UUID id; public UUID getId() { return id; } public void setId(UUID id) { this.id = id; } ...
La classe Physicians:
et la classe Studies:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 @Entity @Table(name = "physicians", schema = "registry") public class Physicians { @EmbeddedId private PhysiciansId id; @Column(name = "name", nullable = false) private String name; ...
Si j'utilise 2 @JoinColumns alors JPA se plaint que:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 @Entity @Table(name = "studies", schema = "registry") public class Studies { @EmbeddedId private StudiesId id; ... @ManyToMany(fetch = FetchType.EAGER) @JoinTable( name = "studies_ord_phys", schema = "registry", joinColumns = {@JoinColumn(name = "study_id"), @JoinColumn(name = "tenant_id")}, inverseJoinColumns = {@JoinColumn(name = "physician_id"), @JoinColumn(name = "tenant_id")} ) private Set<Physicians> ordPhys = new HashSet<>();
Si j'utilise seulement un seul @JoinColumn pour joinColumns et inverseJoinColumns alors:Repeated column in mapping for collection: ...studies.ordPhys column: tenant_id
En SQL c'est facile, je lie simplement studies LEFT JOIN studies_ord_phys USING (tenant_id, study_id) et studies_ord_phys LEFT JOIN physicians USING (tenant_id, physician_id)Physicians from ...studies has the wrong number of column. should be 2
PS: mes tenants ne sont pas complètement séparés et donc la plupart du temps les requêtes se font sur un seul tenant, mais parfois elles se font sur tous les tenants.
J'ai essayé
- de dupliquer le tenant_id dans la table de jointure. Ca marche, je peux alors avoir 2 clefs primaires faites de 2 champs complètement distincts et JPA fonctionne. Mais je trouve cela triste de dupliquer le tenant_id juste pour JPA. Et surtout c'est totalement inefficace parce que je travaille avec Microsoft Citus en faisant du sharding sur le tenant_id ==> la jointure entre studies_ord_phys et physicians se fait avec le clone de tenant_id qui n'est donc pas la clef de sharding ==> super lent ...
- d'ajouter updatable = false, insertable = false sur l'inverseJoinColumn. Ca marche pour la lecture avec un seul tenant_id dans la table de jointure. Mais l'écriture ne marche pas parce qu'Hibernate essaye d'insérer 4 valeurs dans cette table de jointure ne contenant que 3 colonnes.
- de passer par une classe intermédiaire comme proposé par Baeldung à la section 4.2 de cet article mais j'ai la même erreur:
pour ma classe intermédiaire:Repeated column in mapping for entity: com.telemis.tfp.registry.modelspp.StudyOrdPhyLink column: tenant_id (should be mapped with insert="false" update="false")
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 @Id Long id; @ManyToOne @JoinColumns({ @JoinColumn(name="tenant_id", referencedColumnName = "tenant_id"), @JoinColumn(name="study_id", referencedColumnName = "id") }) Studies studylink; @ManyToOne @JoinColumns({ @JoinColumn(name="tenant_id", referencedColumnName = "tenant_id"), @JoinColumn(name="physician_id", referencedColumnName = "id") }) Physicians physicianLink;
D'avance, un tout grand merci pour votre aide !
Partager