2009-07-31 10 views
18

Jak zrobić, aby tabela user_roles definiowała dwie kolumny (ID użytkownika, identyfikator roli) jako złożony klucz podstawowy. powinno być łatwe, po prostu nie może zapamiętać/znaleźć.Jak utworzyć złożony klucz podstawowy (adnotacja java)

W user jednostki:

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

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

W roles jednostki:

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

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

dziękuję.

** SZCZEGÓŁY

Więc jest jeszcze trzecia tabela user_roles (automatycznie generowane przez wyżej), który bierze userID z user podmiotu oraz roleID z roles podmiotu. Teraz potrzebuję tych dwóch kolumn w wygenerowanej tabeli (user_roles), aby były złożonym kluczem podstawowym.

Odpowiedz

22

już miał kilka dobrych odpowiedzi tutaj o tym, jak dokładnie jak pytasz zrobić ..

dla odniesienia niech mi tylko wspomnieć zalecany sposób to zrobić w Hibernate zamiast, który jest użycie klucza zastępczego jako klucz podstawowy, oraz oznaczyć kluczy biznesowych jak NaturalId użytkownika:

Chociaż zalecamy stosowanie zastępczych kluczy jako kluczy podstawowych, ty powinien spróbuj zidentyfikować klucze naturalne dla wszystkich podmiotów. Kluczem naturalnym jest właściwość lub kombinacja właściwości , która jest unikalna i nie-pusta. Jest on również niezmienny. Mapuj właściwości klucza naturalnego wewnątrz elementu . Hibernacja wygeneruje niezbędny klucz unikalny i więzy zerowalne, a jako wynik twoje mapowanie będzie bardziej samoobsługujące.

Zaleca się implementację equals() i hashCode() w celu porównania właściwości klucza naturalnego obiektu w postaci .

W kodzie, używając adnotacji, będzie to wyglądać mniej więcej tak:

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

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

Stosując ten pozwoli Ci zaoszczędzić sporo bólu głowy w dół drogi, a dowiesz się, gdy często trzeba odnośnik/mapuj skomponowany klucz podstawowy.

Znalazłem to na własnej skórze, a na koniec po prostu zrezygnowałem z walki z Hibernate i zamiast tego postanowiłem pójść z prądem. W pełni rozumiem, że może to nie być możliwe w twoim przypadku, ponieważ możesz mieć do czynienia ze starszym oprogramowaniem lub zależnościami, ale chciałem tylko wspomnieć o tym w przyszłości. (jeśli nie możesz tego użyć, może ktoś inny może!)

+0

Nie wiem czy Hibernacja to goi ng, aby dać ci coś więcej niż używanie JPA. –

1

Dziękuję za poprawienie pytania ... i uwzględnienie sugestii.

(Niestety, to jest trochę dziwne, że postfix swoje podmioty z DAOS, ale to nie o to chodzi.)

nie jestem pewien, że jest jakiś problem lewej:

  • dwa podmioty, które opisujesz, mają jeden PK, a nie parę.
  • Tabela połączeń nie ma odpowiadającego elementu, jest zdefiniowana w sposób pośredni przez dwie jednostki i ich relację ManyToMany. Jeśli potrzebujesz trzeciej jednostki, zmień swój zestaw ManyToMany na parę relacji OneToMany i ManyToOne.
+0

ale to nie jest to, co chcę. tutaj wydaje się, że klucz kompozytowy na klasę nie jest generowany automatycznie. Potrzebuję klucz złożony w tabeli user_roles, dla których nie mam żadnej klasy. tabela jest automatycznie generowana z klas użytkownika i roli dao. więc gdybym chciał mieć klucz złożony na przykład userdao, to by działało. ale nie potrzebuję/chcę tego. – b0x0rz

+0

dao postfix jest dziedzictwem od kogoś innego. – b0x0rz

+0

"Istnieje również możliwość odwzorowania relacji wielu do wielu między twoimi klasami." Tak, już to zrobiłem (pytanie). Teraz potrzebuję, aby tabela GENERATED nie była bez klucza podstawowego. I potrzebuję, aby klucz podstawowy był złożonym kluczem podstawowym wszystkich (obu) kolumn w tabeli user_roles. – b0x0rz

2

klucze kompozytowe są wykonane przy użyciu @IdClass (inny sposób korzysta @EmbeddedId i @Embeddable nie jestem pewien, który z nich szukasz) @IdClass jest następujący

@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(); 
    } 
} 

mojej kategorii Tutaj być twoim user_roles oraz nazwę i CreateDate będzie Twój identyfikator użytkownika i RoleId

+0

Tak, ważne jest, że potrzebujesz dodatkowa klasa dla połączonego klucza.Zalecam użycie narzędzia generowania automatycznego mapowania, aby utworzyć warstwę ORM dla ciebie.Mnie osobiście używam Netbeans –

12

Aby spełnić twoje wymagania, możesz odwzorować swoje @ManyToMany jako mapowanie @OneToMany. ten sposób USER_ROLE będzie zawierać zarówno USER_ID i ROLE_ID jako związek klucz podstawowy

pokażę ci, jak:

@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; 
     } 

    } 

} 

pamiętać

Jeśli obiekt ma przypisany identyfikator lub klucz złożony, identyfikator POWINNY BYĆ PRZYWOŁANY do instancji obiektu PRZED wywołaniem save().

Więc stworzyliśmy konstruktora JoinedUserRoleId jak ten, aby dbać o to

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

I wreszcie klasy Rola

@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); 
    } 

} 

Według go przetestować, napiszmy następujący

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(); 

Zawiadomienie do kodu powyżej NO REFERENCE to JoinedUserRole class.

Jeśli chcesz pobrać JoinedUserRole, wypróbuj poniższe

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(); 

pozdrowienia,

+2

Wow, włożyłeś w to dużo pracy! +1 – Tim

1

miałem ten sam problem z kluczy podstawowych. Znałem również rozwiązanie z klasami @Embeddable i @EmbeddedId. Ale chciałem tylko proste rozwiązanie z adnotacjami.

Dobrze znalazłem oświecenie przez ten artykuł: http://www.vaannila.com/hibernate/hibernate-example/hibernate-mapping-many-to-many-using-annotations-1.html

i tutaj jest magia:

ten generuje klucz podstawowy w tabeli sprzężenia:

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

ten nie generuj klucza podstawowego w tabeli łączenia:

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

przynajmniej w moim środowisku

Należy zauważyć, że różnica jest przy użyciu Ustaw lub Lista