2009-07-31 6 views
18

Wie Sie es so einrichten, dass die Tabelle user_roles die beiden Spalten (userID, roleID) als zusammengesetzten Primärschlüssel definiert. sollte einfach sein, kann mich einfach nicht erinnern/finden.So erstellen Sie einen zusammengesetzten Primärschlüssel (Java-Persistenz-Annotation)

In user Einheit:

@ManyToMany(fetch = FetchType.LAZY) 
@JoinTable(name = "user_roles") 
public List<RoleDAO> getRoles() { 
    return roles; 
} 

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
public Integer getUserID() { 
    return userID; 
} 

In roles Einheit:

@ManyToMany(fetch = FetchType.LAZY) 
@JoinTable(name = "user_roles") 
public List<UserDAO> getUsers() { 
    return users; 
} 

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
public Integer getRoleID() { 
    return roleID; 
} 

Danke.

** MEHR INFO

So gibt es eine dritte Tabelle ist user_roles (Auto von oben erzeugt), die userID von user Einheit und roleID von roles Einheit nimmt. Jetzt brauche ich diese zwei Spalten in der generierten Tabelle (user_roles), um ein zusammengesetzter Primärschlüssel zu sein.

Antwort

22

Sie haben schon ein paar gute Antworten hier auf, wie genau, wie Sie fragen .. zu tun hatte

als Referenz möchte ich nur erwähnen, die empfohlene Weg, statt diese in den Ruhezustand zu tun, die einen Ersatzschlüssel als Primärschlüssel zu verwenden ist, und Geschäftsschlüssel als NaturalId des markieren:

Obwohl wir die Verwendung von Ersatzschlüssel als Primärschlüssel empfehlen, Sie sollten Versuchen Sie, die natürlichen Schlüssel für alle Entitäten zu identifizieren. Ein natürlicher Schlüssel ist eine Eigenschaft oder eine Kombination von Eigenschaften , die eindeutig und nicht null ist. Es ist auch unveränderlich. Ordnen Sie die Eigenschaften von dem natürlichen Schlüssel innerhalb des Elements zu. Hibernate wird generieren die erforderlichen eindeutigen Schlüssel und NULL-Einschränkungen und als Ergebnis wird Ihre Zuordnung mehr selbst dokumentieren.

Es wird empfohlen, dass Sie equals() und hashCode() implementieren, um die natürlichen Schlüsseleigenschaften der Entität zu vergleichen.

Im Code Anmerkungen verwenden, würde dies wie folgt aussehen:

@Entity 
public class UserRole { 
    @Id 
    @GeneratedValue 
    private long id; 

    @NaturalId 
    private User user; 
    @NaturalId 
    private Role role; 
} 

diese Verwendung finden Sie eine Menge Kopfschmerzen die Straße hinunter speichern, wie Sie herausfinden werden, wenn Sie häufig haben referenzieren/ordnen Sie den zusammengesetzten Primärschlüssel zu.

Ich fand das auf die harte Tour und am Ende gab ich einfach auf, gegen Hibernate zu kämpfen und entschied mich stattdessen, mit dem Fluss zu gehen. Ich verstehe vollständig, dass dies in Ihrem Fall möglicherweise nicht möglich ist, da Sie möglicherweise mit Legacy-Software oder Abhängigkeiten zu tun haben, aber ich wollte es nur zur späteren Bezugnahme erwähnen. (wenn Sie es vielleicht nicht verwenden können, kann jemand anderes!)

+0

Ich weiß nicht, ob Hibernate goi ist ng, um Ihnen etwas über JPA zu geben. –

1

Vielen Dank für die Verbesserung Ihrer Frage ... und unter Berücksichtigung der Vorschläge.

(Sorry, ist es ein wenig seltsam, dass Sie Ihre Einheiten mit Daos postfix, aber es ist nicht der Punkt.)

Ich bin nicht sicher, ob es irgendein Problem links:

  • Die Zwei Entitäten, die Sie beschreiben, haben jeweils eine PK, nicht ein Paar.
  • Die Verknüpfungstabelle hat keine entsprechende Entität, sie wird implizit durch die beiden Entitäten und ihre ManyToMany-Beziehung definiert. Wenn Sie eine dritte Entität benötigen, ändern Sie Ihre ManyToMany für ein Paar von OneToMany- und ManyToOne-Beziehungen.
+0

verwendet, aber das ist nicht das, was ich will. hier scheint es den zusammengesetzten Schlüssel auf der Klasse zu machen, die nicht automatisch erzeugt wird. Ich brauche einen zusammengesetzten Schlüssel in der Tabelle user_roles, für die ich keine Klasse habe. Die Tabelle wird automatisch aus Benutzer- und Rollen-Dao-Klassen generiert. Wenn ich zum Beispiel einen zusammengesetzten Schlüssel in userdao haben wollte, würde das funktionieren. aber ich brauche/will das nicht. – b0x0rz

+0

Dao Postfix ist Vermächtnis von jemand anderem. – b0x0rz

+0

"Es ist auch möglich, eine Viele-zu-Viele-Beziehung zwischen Ihren beiden Klassen abzubilden." Ja das habe ich schon gemacht (in Frage gestellt). Jetzt brauche ich für diese generierte Tabelle nicht mehr einen Primärschlüssel. UND ich brauche diesen Primärschlüssel als zusammengesetzten Primärschlüssel aller (beiden) Spalten in der Tabelle user_roles. – b0x0rz

2

Composite-Schlüssel verwenden @IdClass getan (die andere Art und Weise verwendet @EmbeddedId und @Embeddable nicht sicher, welchen Sie suchen) die @IdClass als

folgt
@Entity 
@IdClass(CategoryPK.class) 
public class Category { 
    @Id 
    protected String name; 

    @Id 
    protected Date createDate; 

} 

public class CategoryPK implements Serializable { 

    String name; 

    Date createDate; 

    public boolean equals(object other) { 
     //implement a equals that the PP can use to determine 
     //how the CategoryPK object can be identified. 
    } 

    public int hashCode(){ 
     return Super.hashCode(); 
    } 
} 

meine Kategorie wird hier Ihre user_roles und der Name und ErstellDat wird Ihre Benutzer-ID und RoleID

+0

Ja, die Import-Sache ist, dass Sie eine benötigen Zusätzliche Klasse für kombinierten Schlüssel Ich empfehle die Verwendung eines automatischen Mapping-Tools, um die ORM-Ebene für Sie zu erstellen Ich persönlich benutze NetBeans –

12

Um Ihre Anforderung zu erfüllen, können Sie Ihre @ManyToMany als @ OneToMany Mapping zuordnen. Auf diese Weise enthält USER_ROLE sowohl BENUTZER_ID und ROLE_ID als Verbindung Primärschlüssel

Ich werde Ihnen zeigen, wie Sie:

@Entity 
@Table(name="USER") 
public class User { 

    @Id 
    @GeneratedValue 
    private Integer id; 

    @OneToMany(cascade=CascadeType.ALL, mappedBy="joinedUserRoleId.user") 
    private List<JoinedUserRole> joinedUserRoleList = new ArrayList<JoinedUserRole>(); 

    // no-arg required constructor 
    public User() {} 

    public User(Integer id) { 
     this.id = id; 
    } 

    // addRole sets up bidirectional relationship 
    public void addRole(Role role) { 
     // Notice a JoinedUserRole object 
     JoinedUserRole joinedUserRole = new JoinedUserRole(new JoinedUserRole.JoinedUserRoleId(this, role)); 

     joinedUserRole.setUser(this); 
     joinedUserRole.setRole(role); 

     joinedUserRoleList.add(joinedUserRole); 
    } 

} 

@Entity 
@Table(name="USER_ROLE") 
public class JoinedUserRole { 

    public JoinedUserRole() {} 

    public JoinedUserRole(JoinedUserRoleId joinedUserRoleId) { 
     this.joinedUserRoleId = joinedUserRoleId; 
    } 

    @ManyToOne 
    @JoinColumn(name="USER_ID", insertable=false, updatable=false) 
    private User user; 

    @ManyToOne 
    @JoinColumn(name="ROLE_ID", insertable=false, updatable=false) 
    private Role role; 

    @EmbeddedId 
    // Implemented as static class - see bellow 
    private JoinedUserRoleId joinedUserRoleId; 

    // required because JoinedUserRole contains composite id 
    @Embeddable 
    public static class JoinedUserRoleId implements Serializable { 

     @ManyToOne 
     @JoinColumn(name="USER_ID") 
     private User user; 

     @ManyToOne 
     @JoinColumn(name="ROLE_ID") 
     private Role role; 

     // required no arg constructor 
     public JoinedUserRoleId() {} 

     public JoinedUserRoleId(User user, Role role) { 
      this.user = user; 
      this.role = role; 
     } 

     public JoinedUserRoleId(Integer userId, Integer roleId) { 
      this(new User(userId), new Role(roleId)); 
     } 

     @Override 
     public boolean equals(Object instance) { 
      if (instance == null) 
       return false; 

      if (!(instance instanceof JoinedUserRoleId)) 
       return false; 

      final JoinedUserRoleId other = (JoinedUserRoleId) instance; 
      if (!(user.getId().equals(other.getUser().getId()))) 
       return false; 

      if (!(role.getId().equals(other.getRole().getId()))) 
       return false; 

      return true; 
     } 

     @Override 
     public int hashCode() { 
      int hash = 7; 
      hash = 47 * hash + (this.user != null ? this.user.hashCode() : 0); 
      hash = 47 * hash + (this.role != null ? this.role.hashCode() : 0); 
      return hash; 
     } 

    } 

} 

erinnern

Wenn ein Objekt eine zugewiesene Kennung hat, oder ein zusammengesetzter Schlüssel, die Kennung sollte der Objektinstanz vor dem Aufruf von save() zugewiesen werden.

So haben wir einen JoinedUserRoleId Konstruktor wie diese geschaffen, um es zu kümmern

public JoinedUserRoleId(User user, Role role) { 
    this.user = user; 
    this.role = role; 
} 

Und schließlich Rollenklasse

@Entity 
@Table(name="ROLE") 
public class Role { 

    @Id 
    @GeneratedValue 
    private Integer id; 

    @OneToMany(cascade=CascadeType.ALL, mappedBy="JoinedUserRoleId.role") 
    private List<JoinedUserRole> joinedUserRoleList = new ArrayList<JoinedUserRole>(); 

    // no-arg required constructor 
    public Role() {} 

    public Role(Integer id) { 
     this.id = id; 
    } 

    // addUser sets up bidirectional relationship 
    public void addUser(User user) { 
     // Notice a JoinedUserRole object 
     JoinedUserRole joinedUserRole = new JoinedUserRole(new JoinedUserRole.JoinedUserRoleId(user, this)); 

     joinedUserRole.setUser(user); 
     joinedUserRole.setRole(this); 

     joinedUserRoleList.add(joinedUserRole); 
    } 

} 

Laut zu testen, lassen Sie uns schreiben Sie die folgenden

User user = new User(); 
Role role = new Role(); 

// code in order to save a User and a Role 
Session session = HibernateUtil.getSessionFactory().openSession(); 
session.beginTransaction(); 

Serializable userId = session.save(user); 
Serializable roleId = session.save(role); 

session.getTransaction().commit(); 
session.clear(); 
session.close(); 

// code in order to set up bidirectional relationship 
Session anotherSession = HibernateUtil.getSessionFactory().openSession(); 
anotherSession.beginTransaction(); 

User savedUser = (User) anotherSession.load(User.class, userId); 
Role savedRole = (Role) anotherSession.load(Role.class, roleId); 

// Automatic dirty checking 
// It will set up bidirectional relationship 
savedUser.addRole(savedRole); 

anotherSession.getTransaction().commit(); 
anotherSession.clear(); 
anotherSession.close(); 

Hinweis Übereinstimmung Code über NO REFERENCE in der JoinedUserRole-Klasse zu codieren.

Wenn Sie eine JoinedUserRole abrufen möchten, versuchen Sie die folgenden

Session session = HibernateUtil.getSessionFactory().openSession(); 
session.beginTransaction(); 

Integer userId; 
Integer roleId; 

// Lets say you have set up both userId and roleId 
JoinedUserRole joinedUserRole = (JoinedUserRole) session.get(JoinedUserRole.class, new JoinedUserRole.JoinedUserRoleId(userId, roleId)); 

// some operations 

session.getTransaction().commit(); 
session.clear(); 
session.close(); 

Grüßen,

+2

Wow, du hast viel Arbeit investiert! +1 – Tim

1

Ich hatte das gleiche Problem mit den Primärschlüssel. Ich kannte auch die Lösung mit der @ Embeddable und @EmbeddedId Klasse. Aber ich wollte nur die einfache Lösung mit den Anmerkungen.

Nun fand ich Erleuchtung durch diesen Artikel: http://www.vaannila.com/hibernate/hibernate-example/hibernate-mapping-many-to-many-using-annotations-1.html

und hier ist die Magie:

dies erzeugt einen Primärschlüssel auf der Join-Tabelle:

@ManyToMany(cascade = CascadeType.ALL) 
@JoinTable(name="classA_classB") 
private Set<ClassA> classesA; 

dieses generiert keinen Primärschlüssel für die Join-Tabelle:

@ManyToMany(cascade = CascadeType.ALL) 
@JoinTable(name="classA_classB") 
private List<ClassA> classesA; 

zumindest in meiner Umgebung

Beachten Sie, dass die Differenz Set oder Liste

Verwandte Themen