2010-02-03 8 views
6

Ich suchte dort, und habe kein ähnliches Thema gefunden, so posten ich eine neue Frage.Hibernate Composite Primärschlüssel enthält einen zusammengesetzten Fremdschlüssel, wie Sie dies zuordnen

Ich arbeite mit Hibernate auf einer vorhandenen Datenbank. Die Tabellenstruktur und Daten, die wir nicht ändern dürfen. Die Anwendung liest Daten aus der Datenbank und migriert basierend auf einer Logik in einen anderen Datenspeicher.

Jetzt ist das Problem über eine zusammengesetzte PK-Zuordnung. z.B.

Tabelle A hat eine zusammengesetzte PK.

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

Tabelle B hat einen Verbund zu PK, und ein Teil dieses Verbundes PK PK A, hier als FK arbeitet auch.

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

Ich habe mehrere Möglichkeiten ausprobiert, und keiner von ihnen funktioniert. Kann jemand eine funktionierende Hibernate Mapping Lösung erzählen? besser im Annotationsstil.

Antwort

9

Richten Sie das Entitätsobjekt von A als @ManyToOne in Bs pk Class ein.

Also, wenn Sie

Class A 
Class APK - A's Primary Key 

Class B 
Class BPK - B's primary Key. 

BPKA als Attribut

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

Vom documentation

@Embeddable erben die Zugriffstyp seine besitzen Entität enthalten wird, es sei denn der Hibernate spezifische Annotation @AccessType wird verwendet. Zusammengesetzte Fremdschlüssel (falls nicht mit den standardmäßigen sensitiven Werten) sind bei Zuordnungen definiert, die das @JoinColumns-Element verwenden, das im Wesentlichen ein Array von @JoinColumn ist. Es gilt als eine gute Praxis zu Express referencedColumnNames explizit. Andernfalls wird Hibernate annehmen, dass Sie die gleiche Reihenfolge der Spalten wie in der Primärschlüssel Deklaration verwenden.

+0

@Vinodh Ramasubramania Hallo, es ist keine gute Idee, eine Entität als Primärschlüssel zu verwenden. Hibernate Team empfiehlt. Sie können ein Abfrageergebnis in HQL oder Kriterien nicht auf eine Entität beschränken, die als Primärschlüssel verwendet wird. Daher gibt es viele Möglichkeiten, wie Sie vermeiden können, es zu verwenden. –

+0

Aber ich verwende keine Entität als PK. Ich verwende es (A), um eine ManyToOne-Beziehung mit den Join-Bedingungen in der PK von B herzustellen. In Ihrer Lösung sehe ich nicht, wie die zusammengesetzte PK von B (BPK) mit der zusammengesetzten PK von A (APK) definiert ist eine Teilmenge dazu. –

+0

Die OneToMany in Ihrer BPK-Klasse hilft mir. Ich habe nicht in diese Richtung gedacht. Ich habe gerade darüber nachgedacht, wie ich eine andere APK-Klasse in BPK referenzieren soll. Und ich weiß nicht, wie ich die Annotation einstellen soll. Für eine bequeme a.getBset() modellierte ich eine andere One2Many mit Joincolumns in A-Klasse. z.B. privat Set bSet ;. in der TypeB-Klasse auch ein manyToOne, das auf TypeA verweist. natürlich einfügbar, update = false wird benötigt. Danke Jungs. – Kent

3

Wenn Ihre Verbindung Primärschlüssel nur Ersatzschlüssel haben, verwenden @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 

} 

In KlasseA wir

@Entity 
public class ClassA { 

    private CompoundIdA compoundIdA; 

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

} 

haben Wenn Ihre Verbindung Primärschlüssel sowohl natürliche haben und Ersatzschlüssel, erneut verwenden @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; 
    } 

} 

Hinweis Sie müssen einführbare = false und updateable = false einrichten, weil mehr als eine Eigenschaft die gleiche Spalte teilen. Andernfalls wird Hibernate einige Fehler melden.

Wenn Ihre Verbindung Primärschlüssel nur natürliche Schlüssel haben, verwenden @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; 
    } 

} 

In ClassB, können Sie die gleiche Methode verwenden, wie oben gezeigt, aber, wenn Sie einen @ManyToOne definieren möchten Eigenschaft, müssen Sie einführbar = false und aktualisierbar = false wie folgt

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

} 

Grüße eingerichtet,

+0

Ich sehe wirklich keinen großen Unterschied zwischen deiner und meiner Antwort. Außer du hast alternative Anmerkungen für die gleichen Dinge benutzt, die ich skizziert habe. –

+0

Wie schreibe ich ClassB.hbm.xml für das gleiche? – knocker

Verwandte Themen