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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2193756/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 04:37:09  来源:igfitidea点击:

hibernate composite Primary key contains a composite foreign key, how to map this

javahibernatehibernate-annotations

提问by Kent

I searched there, and didn't find any similar topic, so I am posting a new question.

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

I am working with Hibernate on an existing Database. The table structure and data we are not allowed to change. The application is reading data from the database and migrating to another datastore based on some logic.

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

Now the problem is about a composite PK mapping. e.g.

现在的问题是关于复合 PK 映射。例如

Table A has a composite PK.

表 A 有一个复合 PK。

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

Table B has a composite PK too, and one part of this composite PK is A's PK, here is working as FK as well.

表 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
========

I tried several ways, and none of them works. Can anyone tell a working Hibernate mapping solution? better in annotation style.

我尝试了几种方法,但都不起作用。谁能告诉一个有效的 Hibernate 映射解决方案?更好的注释样式。

采纳答案by Vinodh Ramasubramanian

Set up A's entity object as a @ManyToOne in B's pk Class.

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

So if you have

所以如果你有

Class A
Class APK - A's Primary Key

Class B
Class BPK - B's primary Key.

BPKwill contain Aas an attribute

BPK将包含A作为属性

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

From the documentation

文档

@Embeddable inherit the access type of its owning entity unless the Hibernate specific annotation @AccessType is used. Composite foreign keys (if not using the default sensitive values) are defined on associations using the @JoinColumns element, which is basically an array of @JoinColumn. It is considered a good practice to express referencedColumnNames explicitly. Otherwise, Hibernate will suppose that you use the same order of columns as in the primary key declaration.

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

回答by Arthur Ronald

If your compound primary key have onlysurrogate keys, use @EmbeddableId

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

在 ClassA 中,我们有

@Entity
public class ClassA {

    private CompoundIdA compoundIdA;

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

}

If your compound primary key have both natural and surrogate keys, use again @EmbeddableId

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

}

Notice you have to set up insertable=false and updateable=falsebecause more than one property share the same column. Otherwise, Hibernate will complain some errors.

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

If your compound primary key have onlynatural keys, use @IdClass

如果您的复合主键只有自然键,请使用@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, you can use the same approach as shown above, butif you want to define a @ManyToOne property, you have to set upinsertable=false and updateable=false as follows

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

}

regards,

问候,