Mappage de la table d’association plusieurs à plusieurs avec des colonnes supplémentaires

Ma firebase database contient 3 tables: Les entités User et Service ont une relation plusieurs-à-plusieurs et sont jointes à la table SERVICE_USER comme suit:

UTILISATEURS – SERVICE_USER – SERVICES

La table SERVICE_USER contient une colonne supplémentaire BLOCKED.

Quel est le meilleur moyen d’effectuer une telle cartographie? Ce sont mes classes d’entité

@Entity @Table(name = "USERS") public class User implements java.io.Serializable { private Ssortingng userid; private Ssortingng email; @Id @Column(name = "USERID", unique = true, nullable = false,) public Ssortingng getUserid() { return this.userid; } .... some get/set methods } @Entity @Table(name = "SERVICES") public class CmsService implements java.io.Serializable { private Ssortingng serviceCode; @Id @Column(name = "SERVICE_CODE", unique = true, nullable = false, length = 100) public Ssortingng getServiceCode() { return this.serviceCode; } .... some additional fields and get/set methods } 

J’ai suivi cet exemple http://giannigar.wordpress.com/2009/09/04/m … using-jpa / Voici un code de test:

 User user = new User(); user.setEmail("e2"); user.setUserid("ui2"); user.setPassword("p2"); CmsService service= new CmsService("cd2","name2"); List userServiceList = new ArrayList(); UserService userService = new UserService(); userService.setService(service); userService.setUser(user); userService.setBlocked(true); service.getUserServices().add(userService); userDAO.save(user); 

Le problème est que Hibernate persiste Objet utilisateur et UserService. Pas de succès avec l’object CmsService

J’ai essayé d’utiliser EAGER Fetch – pas de progrès

Est-il possible d’atteindre le comportement que j’attends avec la cartographie fournie ci-dessus?

Peut-être y a-t-il une manière plus élégante de mapper plusieurs à plusieurs tables de jointure avec une colonne supplémentaire?

Comme la table SERVICE_USER n’est pas une table de jointure pure, mais des champs fonctionnels supplémentaires (bloqués), vous devez la mapper en tant qu’entité et décomposer l’association de plusieurs à plusieurs entre utilisateur et service en deux associations OneToMany: et un service a plusieurs UserServices.

Vous ne nous avez pas montré la partie la plus importante: la cartographie et l’initialisation des relations entre vos entités (c’est-à-dire la partie avec laquelle vous avez des problèmes). Je vais donc vous montrer à quoi ça doit ressembler.

Si vous faites les relations bidirectionnelles, vous devriez donc avoir

 class User { @OneToMany(mappedBy = "user") private Set userServices = new HashSet(); } class UserService { @ManyToOne @JoinColumn(name = "user_id") private User user; @ManyToOne @JoinColumn(name = "service_code") private Service service; @Column(name = "blocked") private boolean blocked; } class Service { @OneToMany(mappedBy = "service") private Set userServices = new HashSet(); } 

Si vous ne mettez aucune cascade sur vos relations, vous devez alors conserver / sauvegarder toutes les entités. Bien que seul le côté propriétaire de la relation (ici, le côté UserService) doit être initialisé, il est également recommandé de s’assurer que les deux côtés sont cohérents.

 User user = new User(); Service service = new Service(); UserService userService = new UserService(); user.addUserService(userService); userService.setUser(user); service.addUserService(userService); userService.setService(service); session.save(user); session.save(service); session.save(userService); 

Je cherche un moyen de mapper une table d’association plusieurs-à-plusieurs avec des colonnes supplémentaires avec la configuration d’hibernation dans des fichiers xml.

En supposant que vous avez deux tables ‘a’ et ‘c’ avec une association de plusieurs à plusieurs avec une colonne nommée ‘extra’. Parce que je n’ai pas trouvé d’exemple complet, voici mon code. J’espère que ça va aider :).

Premièrement, voici les objects Java.

 public class A implements Serializable{ protected int id; // put some others fields if needed ... private Set ac = new HashSet(); public A(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public Set getAC() { return ac; } public void setAC(Set ac) { this.ac = ac; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 97; int result = 1; result = prime * result + id; return result; } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof A)) return false; final A other = (A) obj; if (id != other.getId()) return false; return true; } } public class C implements Serializable{ protected int id; // put some others fields if needed ... public C(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 98; int result = 1; result = prime * result + id; return result; } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof C)) return false; final C other = (C) obj; if (id != other.getId()) return false; return true; } } 

Maintenant, nous devons créer la table d’association. La première étape consiste à créer un object représentant une clé primaire complexe (a.id, c.id).

 public class ACId implements Serializable{ private A a; private C c; public ACId() { super(); } public A getA() { return a; } public void setA(A a) { this.a = a; } public C getC() { return c; } public void setC(C c) { this.c = c; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((a == null) ? 0 : a.hashCode()); result = prime * result + ((c == null) ? 0 : c.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ACId other = (ACId) obj; if (a == null) { if (other.a != null) return false; } else if (!a.equals(other.a)) return false; if (c == null) { if (other.c != null) return false; } else if (!c.equals(other.c)) return false; return true; } } 

Créons maintenant l’object d’association lui-même.

 public class AC implements java.io.Serializable{ private ACId id = new ACId(); private Ssortingng extra; public AC(){ } public ACId getId() { return id; } public void setId(ACId id) { this.id = id; } public A getA(){ return getId().getA(); } public C getC(){ return getId().getC(); } public void setC(CC){ getId().setC(C); } public void setA(AA){ getId().setA(A); } public Ssortingng getExtra() { return extra; } public void setExtra(Ssortingng extra) { this.extra = extra; } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AC that = (AC) o; if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false; return true; } public int hashCode() { return (getId() != null ? getId().hashCode() : 0); } } 

À ce stade, il est temps de cartographier toutes nos classes avec la configuration hibernate xml.

A.hbm.xml et C.hxml.xml (qui sont identiques).

    a_id_seq               c_id_seq    

Et puis le fichier de mappage d’association, a_c.hbm.xml.

        

Voici l’exemple de code à tester.

 A = ADao.get(1); C = CDao.get(1); if(A != null && C != null){ boolean exists = false; // just check if it's updated or not for(AC a : a.getAC()){ if(a.getC().equals(c)){ // update field a.setExtra("extra updated"); exists = true; break; } } // add if(!exists){ ACId idAC = new ACId(); idAC.setA(a); idAC.setC(c); AC AC = new AC(); AC.setId(idAC); AC.setExtra("extra added"); a.getAC().add(AC); } ADao.save(A); } 

Comme dit précédemment, avec JPA, pour avoir la possibilité d’avoir des colonnes supplémentaires, vous devez utiliser deux associations OneToMany, au lieu d’une seule relation ManyToMany. Vous pouvez également append une colonne avec des valeurs générées automatiquement; De cette façon, il peut fonctionner comme clé primaire de la table, si cela est utile.

Par exemple, le code d’implémentation de la classe supplémentaire devrait ressembler à ceci:

 @Entity @Table(name = "USER_SERVICES") public class UserService{ // example of auto-generated ID @Id @Column(name = "USER_SERVICES_ID", nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private long userServiceID; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "USER_ID") private User user; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "SERVICE_ID") private Service service; // example of extra column @Column(name="VISIBILITY") private boolean visibility; public long getUserServiceID() { return userServiceID; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public Service getService() { return service; } public void setService(Service service) { this.service = service; } public boolean getVisibility() { return visibility; } public void setVisibility(boolean visibility) { this.visibility = visibility; } }