2009-09-23 18 views
5

Oto złożony klucz podstawowy dla jednego z moich podmiotów.@IdClass JPA Adnotacja

public class GroupMembershipPK implements Serializable{ 

    private static final long serialVersionUID = 7816433876820743311L; 

    private User user; 
    private Group group; 

    public GroupMembershipPK(){ 
    } 

    public boolean equals(Object o){ 
     if(o==null){ 
      return false; 
     } 

     if(o instanceof GroupMembershipPK){ 
      final GroupMembershipPK groupMembershipPK=(GroupMembershipPK)o; 
      return groupMembershipPK.group.getGroupName().equals(this.group.getGroupName()) && 
       groupMembershipPK.user.getName().equals(this.user.getName()); 
     } 
     return false; 
    } 

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

Oto moja jednostka (część) z wykorzystaniem powyższego jako złożonego klucza podstawowego.

@Entity 
@IdClass(GroupMembershipPK.class) 
public class GroupMembership extends AbstractModelElementVersionOther{ 

    private static final long serialVersionUID = 9188465566607060376L; 

    private String memType; 
    private Group group; 
    private User user; 

    public GroupMembership(){ 
     super(); 
    } 

    @Column(nullable=false) 
    public String getMemType(){ 
     return this.memType; 
    } 

    public void setMemType(String memType){ 
     this.memType=memType; 
    } 

    @Id 
    @ManyToOne 
    @JoinColumn(name="groupId") 
    public Group getGroup(){ 
     return this.group; 
    } 

    public void setGroup(Group group){ 
     this.group=group; 
    } 

    @Id 
    @ManyToOne 
    @JoinColumn(name="userId") 
    public User getUser(){ 
     return this.user; 
    } 

    public void setUser(User user){ 
     this.user=user; 
    } 

    @Override 
    public boolean equals(Object o) { 
// 

Jestem trochę zdezorientowany na temat tego, jak powinna wyglądać implementacja metody równości dla powyższego podmiotu. Jak mogę porównać dwa złożone klucze podstawowe?

Wszelkie komentarze na temat innych części mojego kodu są również mile widziane.

Odpowiedz

7

Nie jest dobrym pomysłem przechowywanie elementów jako klucza podstawowego. Istnieją pewne ograniczenia, gdy używanie języka zapytań i JPA 1.0 nie jest obsługiwane. Poza tym nie ma potrzeby używania jednostek jako klucza podstawowego. Pomyśl o it.If chcesz podjąć specjalną spojrzeć na następujące pytanie

A class that behaves like @Entity and @Embeddable

Answer one

Comment about answer one

Zobaczysz, że przy użyciu podmiotu jako klucz podstawowy nie jest konieczne.

Zamiast

public class GroupMembershipPK implements Serializable { 

    private User user; 
    private Group group; 

} 

Zastosowanie

public class GroupMembershipPK implements Serializable { 

    private Integer userId; 
    private Integer groupId; 

} 

równa realizacja jest ważna, ponieważ JPA porównuje dwa podmioty używając go (JPA sprawdza, czy dany podmiot jest w kontekście utrwalania za pomocą równa wdrożenia). Więc można wdrożyć według

public boolean equals(Object o) { 
    if(o == null) 
     return false; 

    if(!(o instanceof GroupMembershipPK)) 
     return false; 

    GroupMembershipPK other = (GroupMembershipPK) o; 
    if(!(getUserId().equals(other.getUserId())) 
     return false; 

    if(!(getGroupId().equals(other.getGroupId())) 
     return false; 

    return true; 
} 

rada: to jest dobry pomysł użyć dostępu właściwość zamiast dostęp pola, ponieważ w niektórych czasach, wdrażanie WZP używa obiektu proxy z powodu problemów z wydajnością. Obiekt proxy korzysta z dostępu do właściwości, ponieważ umożliwia implementację JPA, gdy jest to konieczne, trafia do bazy danych.

Jak zapisać obiekt korzystający z złożonego klucza podstawowego?

User user = new user(); 
Group group = new Group(); 

entityManager.save(user); 
entityManager.save(group); 

entityManager.flush(); 

UserGroup userGroup = new UserGroup(); 

userGroup.setId(new UserGroup.UserGroupId(user.getId(), group.getId())); 

entityManager.save(userGroup); 

Chcesz dowiedzieć się, jak zaimplementować UserGroup?

public class UserGroup { 

    private UserGroupId id; 

    // You can create UserGroupId outside UserGroup class 
    // Feel free to choice your best approach 
    @Embeddable 
    public static class UserGroupId implements Serializable { 

     private Integer userId; 
     private Integer groupId; 

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

     public UserGroupId(Integer userId, Integer groupId) { 
      this.userId = userId; 
      this.roupId = groupId; 
     } 

     // getter's and setter's 

     // equals and hashcode as shown above 

    } 

    @EmbeddedId 
    public UserGroupId getId() { 
     return this.id; 
    } 

    public setId(UserGroupId id) { 
     this.id = id; 
    } 
} 

Innym podejściem do stosowania złożonego klucza podstawowego jest IdClass. Zobacz IdClass

Pozdrowienia,

+0

Należy również zaimplementować metodę hashCode który używa identyfikatora użytkownika i właściwości GroupID, ponieważ równe obiekty muszą mieć ten sam hash. Na przykład: (getUserId() == null? 0: getUserId(). HashCode())^(getGroupId() == null? 0: getGroupId(). HashCode()) –

+0

@ Jörn Horstmann Witaj, jesteś dobrze. Ale zaimplementowano tylko równe wdrożenie z powodu odpowiedzi. I tak dziękuję –

+0

@Arthur Ronald. Dzięki, działa idealnie. Czy możesz mi jednak powiedzieć, jak utrzymywać encję przy użyciu złożonego klucza podstawowego, jak opisano powyżej? Otrzymuję następujący błąd w JBoss, gdy próbuję to zrobić .------- "Wyjątek w wątku" główny "javax.ejb.EJBException: javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: id dla klasa ta musi być ręcznie przypisana przed wywołaniem save() " – soontobeared

1

wspomniano w części, w każdym razie:

  1. Przy realizacji sposobu equals, należy użycie instanceof, aby umożliwić porównanie z podklasy. Jeśli leniwy w trybie hibernacji ładuje relację jeden do jeden lub wiele do jednego, zamiast klasy zwykłej będzie mieć proxy dla klasy. Proxy jest podklasą. Porównywanie nazw klas zakończy się niepowodzeniem.
    Bardziej technicznie, powinieneś postępować zgodnie z Liskovs Substitution Principle i zignorować symetrię.
  2. Następną pułapką jest użycie czegoś takiego jak name.equals(that.name) zamiast name.equals(that.getName()). Pierwsza zawiedzie, jeśli jest to proxy.

http://www.laliluna.de/jpa-hibernate-guide/ch06s06.html