2010-02-03 16 views
6

Busqué allí, y no encontré ningún tema similar, entonces estoy publicando una nueva pregunta.hibernate compuesta La clave principal contiene una clave foránea compuesta, cómo mapear esto

Estoy trabajando con Hibernate en una base de datos existente. La estructura de la tabla y los datos que no podemos cambiar. La aplicación está leyendo datos de la base de datos y migrando a otro almacén de datos en función de cierta lógica.

Ahora el problema es sobre una asignación de PK compuesta. p.ej.

La Tabla A tiene un PK compuesto.

Table A 
-------- 
a1 (pk) 
a2 (pk) 
a3 (pk) 
a4 (pk) 
foo 
bar 
======== 

Tabla B tiene una PK compuesta también, y una parte de este compuesto es PK PK A, aquí está trabajando como FK también.

Table B 
-------- 
a1 (fk,pk) 
a2 (fk,pk) 
a3 (fk,pk) 
a4 (fk,pk) 
b1 (pk) 
b2 (pk) 
b3 (pk) 
foo 
bar 
======== 

Probé de varias maneras, y ninguna de ellas funciona. ¿Alguien puede decir una solución de mapeo de Hibernate en funcionamiento? mejor en el estilo de anotación

Respuesta

9

Configure el objeto de entidad de A como @ManyToOne en la clase pk de B.

Así que si usted tiene

Class A 
Class APK - A's Primary Key 

Class B 
Class BPK - B's primary Key. 

BPK contendrá A como un atributo

@Embeddable 
public class BPK implements serializable { 
    .... 
    private A a; 

    @ManyToOne(fetch=FetchType.EAGER) 
    @JoinColumns ({ 
    @JoinColumn(name="...", referencedColumnName = "..."), 
    @JoinColumn(name="...", referencedColumnName = "..."), 
    ... 
    }) 
    public getA() { 
    return this.a; 
    } 
} 

Desde el documentation

@Embeddable heredar el tipo de acceso de su entidad propietaria menos Hibernate anotación específica @AccessType es utilizada. Las claves externas compuestas (si no es utilizando los valores confidenciales predeterminados) se definen en asociaciones que utilizan el elemento @JoinColumns, que es básicamente una matriz de @JoinColumn. Es se considera una buena práctica para expresamente referenciadoColumnNames explícitamente. De lo contrario, Hibernate indicará que utiliza el mismo orden de columnas que en la declaración de la clave principal .

+0

@Vinodh Ramasubramania Hola, no es una buena idea usar una entidad como clave principal. El equipo de Hibernate lo recomienda. No puede restringir un resultado de consulta en HQL o Criterios en una entidad utilizada como clave principal. Por lo tanto, hay muchas formas en que puede evitar usarlo. –

+0

Pero no estoy usando una entidad como PK. Lo estoy usando (A) para establecer una relación ManyToOne con las condiciones de unión en el PK de B. En su solución, no veo cómo se define el PK compuesto de B (BPK) con el PK compuesto de A (APK) como un subconjunto a esto. –

+0

El OneToMany en su clase BPK me ayuda. No pensé en esa dirección. Seguí pensando cómo hacer referencia a otra clase de APK en BPK. Y no sé cómo configurar la anotación. Para un práctico a.getBset(), modelé otro One2Many con joincolumns en clase A. p.ej. conjunto privado bSet ;. en la clase TypeB, también un manyToOne, que apunta a TypeA. Por supuesto insertable, updatable = false son necesarios. Gracias chicos. – Kent

3

Si la clave principal compuesto tiene sólo claves suplentes, el uso @EmbeddableId

@Embeddable 
public class CompoundIdA implements Serializable { 

    private Integer field0; 
    private Integer field1; 
    private Integer field2; 
    private Integer field3; 

    @Column(name="FIELD_0") 
    public Integer getField0() { 
     return this.field0; 
    } 

    @Column(name="FIELD_1") 
    public Integer getField1() { 
     return this.field1; 
    } 

    @Column(name="FIELD_2") 
    public Integer getField2() { 
     return this.field2; 
    } 

    @Column(name="FIELD_3") 
    public Integer getField3() { 
     return this.field3; 
    } 

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

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

     final CompoundIdA other = (CompoundIdA) o; 
     if(!(getField0().equals(other.getField0())) 
      return false; 

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

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

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

     return true; 
    } 

    // hashcode impl 

} 

En claseA, tenemos

@Entity 
public class ClassA { 

    private CompoundIdA compoundIdA; 

    @EmbeddedId 
    public CompoundIdA getCompoundIdA() { 
     return this.CompoundIdA; 
    } 

} 

Si la clave principal compuesto tiene tanto naturales como claves sustitutas, utilizar nuevamente @EmbeddableId

// Let's suppose field0 and field1 are both natural keys 
@Entity 
public class ClassA { 

    private CompoundIdA compoundIdA; 

    private Integer field0; 
    private Integer field1; 

    @EmbeddedId 
    public CompoundIdA getCompoundIdA() { 
     return this.CompoundIdA; 
    } 

    @Column(name="FIELD_0", insertable=false, updateable=false) 
    public Integer getField0() { 
     return this.field0; 
    } 

    @Column(name="FIELD_1", insertable=false, updateable=false) 
    public Integer getField1() { 
     return this.field1; 
    } 

} 

Aviso tiene que configurar insertable = falso y actualizable = falso porque más de una propiedad comparten la misma columna. De lo contrario, Hibernate se quejará de algunos errores.

Si su clave primaria compuesta tiene sólo claves naturales, utilizar @IdClass

@Entity 
@IdClass(CompoundIdA.class) 
public class ClassA { 

    private Integer field0; 
    private Integer field1; 
    private Integer field2; 
    private Integer field3; 

    @Id 
    @Column(name="FIELD_0") 
    public Integer getField0() { 
     return this.field0; 
    } 

    @Id 
    @Column(name="FIELD_1") 
    public Integer getField1() { 
     return this.field1; 
    } 

    @Id 
    @Column(name="FIELD_2") 
    public Integer getField2() { 
     return this.field2; 
    } 

    @Id 
    @Column(name="FIELD_3") 
    public Integer getField3() { 
     return this.field3; 
    } 

} 

En ClassB, puede utilizar el mismo enfoque que se muestra arriba, pero si desea definir un @ManyToOne propiedad, usted tiene que configurar insertable = falso y actualizable = false de la siguiente manera

@Entity 
public class ClassB { 

    private ClassA classA; 

    @ManyToOne 
    @JoinColumns ({ 
     @JoinColumn(name="FIELD_0", referencedColumnName="FIELD_0", insertable=false, updateable=false), 
     @JoinColumn(name="FIELD_1", referencedColumnName="FIELD_1", insertable=false, updateable=false), 
     @JoinColumn(name="FIELD_2", referencedColumnName="FIELD_2", insertable=false, updateable=false), 
     @JoinColumn(name="FIELD_3", referencedColumnName="FIELD_3", insertable=false, updateable=false) 
    }) 
    public ClassA getClassA() { 
     return this.classA; 
    } 

} 

respecto,

+0

Realmente no veo mucha diferencia entre tu respuesta y la mía. Excepto que ha usado anotaciones alternativas para las mismas cosas que he delineado. –

+0

¿cómo escribo ClassB.hbm.xml para lo mismo? – knocker

Cuestiones relacionadas