2012-04-22 10 views
7

Ich habe ein ziemlich Standard-Szenario, wobei ich eine Tabelle der Benutzer mit user_id als PK und eine Tabelle der Rollen mit role_id als PK haben. Die beiden Tabellen sind über eine Viele-zu-Viele-Beziehung verbunden (dh Benutzer können viele Rollen haben und eine Rolle kann auf viele Benutzer angewendet werden) und anschließend habe ich eine Verbindungstabelle namens users_has_roles. Die einzigen zwei Spalten in users_has_roles sind users_user_id und roles_role_id.JPA persistent viele zu viele

Ich habe die Entity-Klassen generiert (siehe unten) und ich habe kein Problem, Daten in den Benutzer- und Rollentabellen persistent zu speichern, aber ich habe es versäumt, irgendetwas an der Joined-Tabelle users_has_roles festzuhalten, so dass derzeit keinem meiner Benutzer eine Rolle zugewiesen wird . Bevor ich verrückt werde, könnte mich jemand aus meinem Elend herausbringen und mir zeigen, wie ich eine users_user_id mit einer entsprechenden role_role_id zur Tabelle users_has_roles hinzufügen soll, damit meine Benutzer Rollen haben können?

Meine Users.java Entitätsklasse:

@Entity 
@Table(name = "users") 
@XmlRootElement 
@NamedQueries({ 
@NamedQuery(name = "Users.findAll", query = "SELECT u FROM Users u"), 
@NamedQuery(name = "Users.findByUserId", query = "SELECT u FROM Users u WHERE u.userId = :userId"), 
@NamedQuery(name = "Users.findByUsername", query = "SELECT u FROM Users u WHERE u.username = :username"), 
@NamedQuery(name = "Users.findByPassword", query = "SELECT u FROM Users u WHERE u.password = :password")}) 
public class Users implements Serializable { 
private static final long serialVersionUID = 1L; 
@Id 
@Basic(optional = false) 
@NotNull 
@Size(min = 1, max = 60) 
@Column(name = "user_id") 
private String userId; 
@Basic(optional = false) 
@NotNull 
@Pattern(regexp="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", message="Invalid email") 
@Size(min = 1, max = 45) 
@Column(name = "username") 
private String username; 
@Basic(optional = false) 
@NotNull 
@Size(min = 1, max = 120) 
@Column(name = "password") 
private String password; 
@JoinTable(name = "users_has_roles", joinColumns = { 
    @JoinColumn(name = "users_user_id", referencedColumnName = "user_id")}, inverseJoinColumns = { 
    @JoinColumn(name = "roles_role_id", referencedColumnName = "role_id")}) 
@ManyToMany 
private Collection<Roles> rolesCollection; 
@OneToMany(cascade = CascadeType.ALL, mappedBy = "usersUserId") 
private Collection<UserAccount> userAccountCollection; 
@OneToMany(cascade = CascadeType.ALL, mappedBy = "usersUserId") 
private Collection<UserDetails> userDetailsCollection; 

... 

All the getter and setter methods etc. 

Meine Roles.java Entitätsklasse:

@Entity 
@Table(name = "roles") 
@XmlRootElement 
@NamedQueries({ 
@NamedQuery(name = "Roles.findAll", query = "SELECT r FROM Roles r"), 
@NamedQuery(name = "Roles.findByRoleId", query = "SELECT r FROM Roles r WHERE r.roleId = :roleId"), 
@NamedQuery(name = "Roles.findByRoleName", query = "SELECT r FROM Roles r WHERE r.roleName = :roleName"), 
@NamedQuery(name = "Roles.findByRolePermission", query = "SELECT r FROM Roles r WHERE r.rolePermission = :rolePermission"), 
@NamedQuery(name = "Roles.findByRoleDescription", query = "SELECT r FROM Roles r WHERE r.roleDescription = :roleDescription")}) 
public class Roles implements Serializable { 
private static final long serialVersionUID = 1L; 
@Id 
@Basic(optional = false) 
@NotNull 
@Size(min = 1, max = 60) 
@Column(name = "role_id") 
private String roleId; 
@Basic(optional = false) 
@NotNull 
@Size(min = 1, max = 45) 
@Column(name = "role_name") 
private String roleName; 
@Basic(optional = false) 
@NotNull 
@Size(min = 1, max = 45) 
@Column(name = "role_permission") 
private String rolePermission; 
@Size(max = 45) 
@Column(name = "role_description") 
private String roleDescription; 
@ManyToMany(mappedBy = "rolesCollection") 
private Collection<Users> usersCollection; 

... 

All the getter and setter methods etc. 

Dank

---- ---- UPDATE

// New Users 
Users currentUser = new Users(); 
currentUser.setUserId(userId); 
currentUser.setUsername(email); 
currentUser.setPassword(password); 
getUsersFacade().create(currentUser); 

Antwort

6

Ihr Beispiel funktioniert gut (EclipseLink 2.3, MySQL). Wahrscheinlich ist ein Teil des Codes, den Sie nicht zeigen. Zum Beispiel beim Hinzufügen eines Elements zu rolesCollection. Ein typischer Fehler besteht beispielsweise darin, ein Element nur der nicht besitzenden Seite hinzuzufügen.

Für persistierende es müssen Sie kümmern sich um Beziehung in besitzende Seite (eine ohne mappedBy), um auch In-Memory-Objekt Grafik konsistent mit Datenbank zu halten, sollten Sie immer beide Seiten der Beziehung ändern.

Ich versuchte es mit folgenden:

// method to add element to rolesCollection 
    public void addRoles(Roles r) { 
     rolesCollection.add(r); 
    } 

    //first created new instances of Users and Roles 
    // then: 
    tx.begin(); 
    users.addRoles(r); 
    //it is not needed for persisting, but here you can also 
    //add user to roles. 
    em.persist(users); 
    em.persist(r); 
    tx.commit(); 
+1

Hallo Mikko, ich bin immer noch verwirrt! Ich verstehe nicht, wie der obige Code funktioniert.Wenn ich beide Seiten der Relation ändern muss, muss ich sowohl rolesCollection als auch usersCollection Elemente hinzufügen? Es sieht so aus, als ob Sie nur zur rolesCollection hinzufügen. Auch ich bin verwirrt was ich den jeweiligen Collections hinzufüge. Erfordert die rolesCollection sowohl eine users_user_id als auch eine roles_role_id? – tarka

+0

Die Sache ist: zu machen ist in der Datenbank beharrt, Mindestanforderungen ist, besitzende Seite (eine ohne mappedBy) zu ändern. Ein schlechter Punkt ist, dass die Sammlung mit mappedBy nicht synchron ist. Aus diesem Grund ist es im Allgemeinen besser, beide Seiten zu ändern, was bedeutet, dass Elemente sowohl zu rolesCollection als auch zu rolesCollection hinzugefügt werden. –

+0

Ok, also best Practice ist das Hinzufügen von Elementen zu beiden Sammlungen ... aber was füge ich zu jeder Sammlung hinzu? füge ich beiden eine a user_id und eine role_id zu beiden hinzu? – tarka

8

Ok zunächst einmal dank Mikko für mich auf die Antwort führt. Ich wollte nur eine Antwort schreiben, die für jeden anderen hilfreich sein könnte, der in der Position sein könnte, in der ich mich befand. Auch dies basiert auf einem Eureka-Moment, also ist es vielleicht nicht technisch korrekt, aber so sehe ich es.

Das große Problem, dem ich gegenüberstehe, war, dass ich in MySQL die Bridging-Tabelle als einzelne Tabelle sehen konnte! (Es tut mir leid, dass ich kein Bild von meinem EER-Diagramm posten kann, aber im Moment scheint ich nicht genug Privilegien zu haben) Also nahm ich an, dass Java den Überbrückungstisch auch als Tabelle sehen würde! Nun, das tut es nicht. Diese Überbrückungstabelle existiert in Java nicht wirklich als eine herkömmliche Tabelle, sondern wird tatsächlich durch die Sammlungsart der gegenüberliegenden Tabellen dargestellt, die Sie damit verknüpfen.

Der einfachste Weg, es für mich zu sehen, war, die Überbrückungstabelle vollständig zu vergessen und sich auf die zwei "echten" Tabellen zu konzentrieren und die Daten in diesen zu verknüpfen. Der folgende Code ist NICHT die beste Vorgehensweise, da ich einfach die role_id festlege, aber es ist in Ordnung, nur meinen Punkt zu zeigen.

Hoffen, dass das hilft jedem anderen, der mit vielen zu vielen Beziehungen kämpft.

(NB. Ich habe die ursprüngliche Frage Code bearbeitet für eine einfache statt einer Sammlung eine Liste zu verwenden, aber Sie können genauso gut jede andere Art verwenden, die Ihren Bedürfnissen entspricht.)