代码之家  ›  专栏  ›  技术社区  ›  Kent

Hibernate复合主键包含复合外键,如何映射

  •  6
  • Kent  · 技术社区  · 15 年前

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

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

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

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

    我试过几种方法,但都不管用。有人能告诉正在工作的休眠映射解决方案吗?更好的注释样式。

    2 回复  |  直到 9 年前
        1
  •  9
  •   Vinodh Ramasubramanian    15 年前

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

    如果你有

    Class A
    Class APK - A's Primary Key
    
    Class B
    Class BPK - B's primary Key.
    

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

    documentation

    @可嵌入继承的访问类型 它的拥有实体,除非休眠 特定注释@accesstype为 已使用。复合外键(如果不是 使用默认敏感值) 在关联上使用 @joinColumns元素,即 基本上是@joincolumn的数组。它 被认为是 快速引用列名称 明确地。否则,休眠将 假设您使用相同的顺序 列与主键中的列相同 宣言。

        2
  •  3
  •   Arthur Ronald    15 年前

    如果你的复合主键有 只有 代理键,使用@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
    
    }
    

    在课堂上,我们有

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

    在B类中,您可以使用如上所示的方法, 但是 如果要定义@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;
        }
    
    }
    

    当做,