hibernate composite主键包含一个复合外键,如何映射这个

时间:2010-02-03 17:04:26

标签: java hibernate hibernate-annotations

我在那里搜索,但没有找到任何类似的话题,所以我发布了一个新问题。

我正在使用现有数据库上的Hibernate。我们不允许更改表结构和数据。应用程序正在从数据库中读取数据,并根据某些逻辑迁移到另一个数据存储区。

现在的问题是关于复合PK映射。 e.g。

表A具有复合PK。

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

表B也有一个复合PK,这个复合PK的一部分是A的PK,这里也用作FK。

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

我尝试了几种方法,但没有一种方法可行。谁能告诉一个有效的Hibernate映射解决方案?注释风格更好。

2 个答案:

答案 0 :(得分:9)

在B的pk Class中将A的实体对象设置为@ManyToOne。

所以,如果你有

Class A
Class APK - A's Primary Key

Class B
Class BPK - B's primary Key.

BPKA作为属性

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

来自documentation

  

@Embeddable继承了访问类型   它拥有的实体,除非Hibernate   特定注释@AccessType是   用过的。复合外键(如果没有   使用默认敏感值)   在使用的关联上定义   @JoinColumns元素,即   基本上是一个@JoinColumn数组。它   被认为是一种很好的做法   表达referencedColumnNames   明确。否则,Hibernate会   假设您使用相同的顺序   列中的列与主键中一样   声明。

答案 1 :(得分:3)

如果您的复合主键具有代理键,请使用@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

}

在ClassA中,我们有

@Entity
public class ClassA {

    private CompoundIdA compoundIdA;

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

}

如果复合主键具有自然键和代理键,请再次使用@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;
    }

}

注意您必须设置insertable = false和updateable = false ,因为多个属性共享同一列。否则,Hibernate会抱怨一些错误。

如果您的复合主键具有自然键,请使用@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;
    }

}

在ClassB中,您可以使用与上面所示相同的方法,如果您想要定义@ManyToOne属性,您必须设置 insertable = false并且updateable = false如下

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

}

的问候,