2009-09-23 13 views
5

Aquí hay una clave primaria compuesta para una de mis entidades.@IdClass Anotación JPA

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

Heres my entity (part of) utilizando lo anterior como clave primaria compuesta.

@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) { 
// 

Estoy un poco confundido sobre lo que debería ser la implementación del método igual para la entidad anterior. ¿Cómo puedo comparar dos claves primarias compuestas?

También son bienvenidos los comentarios sobre otras partes de mi código.

Respuesta

7

No es una buena idea que almacene entidades como clave principal. Existen algunas limitaciones al usar lenguaje de consulta y JPA 1.0 no es compatible. Además de esto, no es necesario usar entidades como clave principal. Piense en it.If desea, tome una mirada especial a la siguiente pregunta

A class that behaves like @Entity and @Embeddable

Answer one

Comment about answer one

Usted verá que el uso de una entidad como clave principal no es necesario.

En lugar de

public class GroupMembershipPK implements Serializable { 

    private User user; 
    private Group group; 

} 

Uso

public class GroupMembershipPK implements Serializable { 

    private Integer userId; 
    private Integer groupId; 

} 

es igual a la aplicación APP es importante porque compara dos entidades mediante su uso (JPA cheques si una entidad está en contexto de persistencia mediante el uso de la aplicación es igual). Para que puedan aplicar conforme a

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

Consejo: es una buena idea que utilice acceso a la propiedad en lugar de acceso en campo, ya que, en algunos momentos, la aplicación APP utiliza un objeto proxy debido a problemas de rendimiento. Un objeto proxy hace uso del acceso a la propiedad porque permite que la implementación de JPA llegue a la base de datos cuando sea necesario.

Cómo guardar un objeto que usa una clave primaria compuesta?

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

¿Desea saber cómo implementar 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; 
    } 
} 

Otro método para utilizar la clave primaria compuesta es IdClass. Ver IdClass

cordiales,

+0

También debe implementar un método hashCode que utiliza el ID de usuario y las propiedades GROUPID, ya que los objetos iguales también deben tener el mismo hash. Por ejemplo: (getUserId() == null? 0: getUserId(). HashCode())^(getGroupId() == null? 0: getGroupId(). HashCode()) –

+0

@ Jörn Horstmann Hola, eres derecho. Pero se ha implementado solo equivale a la implementación debido a la respuesta. Gracias de todos modos –

+0

@Arthur Ronald. Gracias, funciona a la perfección. Sin embargo, ¿puede decirme cómo persistir la entidad utilizando una clave primaria compuesta como se describe arriba? Obtengo el siguiente error en JBoss cuando intento hacer eso .------- "Excepción en el hilo" main "javax.ejb.EJBException: javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: ids for esta clase debe asignarse manualmente antes de llamar a save() " – soontobeared

1

Se mencionó en parte, de todos modos:

  1. Al implementar el método equals, debe uso instanceof para permitir la comparación con las subclases. Si Hibernate perezosa carga una relación uno a uno o muchos a uno, tendrá un proxy para la clase en lugar de la clase simple. Un proxy es una subclase. Comparar los nombres de clase fallaría.
    Más técnicamente, debe seguir el Liskovs Substitution Principle e ignorar la simetría.
  2. El siguiente inconveniente es usar algo como name.equals(that.name) en lugar de name.equals(that.getName()). El primero fallará, si eso es un proxy.

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

Cuestiones relacionadas