Hibernate的问题:外键必须有相同的列数为引用的主键(Hibernate Issue : Fo

2019-07-18 16:14发布

目标:我想有importJobId在ImportJob作为分配表的ID外键,这样当我们有importJobId然后再只有我们可以在分配ID为没有工作不能有任何分配。

ImportJob表有复合主键[ORGID,IMPORTJOBTYPE],我试图让使用建立在Hibernate外键关系

  <id name="id"
        column="ID">
        <generator class="native"/>
    </id>
    <many-to-one name="importjobid"
                 class="com.delta.pdo.admin.ImportJob"
                 cascade="save-update"/>

在Allocation.hbm.xml这是不工作和我收到错误消息:

Foreign key (FKB29B5F7366007086:ALLOCATIONS [importjobid])) 
must have same number of columns as the 
referenced primary key (IMPORTJOBMANAGMENT [ORGID,IMPORTJOBTYPE])

这里是我的ImportJob.hbm.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.delta.pdo.admin.ImportJob" table="IMPORTJOB" lazy="false">
        <!-- we don't cache this since the commissions code is too screwed up to work with -->
        <composite-id>
            <key-property name="orgId" type="long" column="ORGID"/>
            <key-property name="importJobType" type="java.lang.String" column="IMPORTJOBTYPE"/>
        </composite-id>

        <!-- Make sure importjobid is not-null='true '-->
        <property name="importjobid" type="long" column="IMPORTJOBID" />
        <property name="allocations" type="boolean" column="ALLOCATIONS" />
    </class>
</hibernate-mapping>

下面是bean类以供参考:

public class AllocationBean extends WorkbenchBeanBase
{
    private static final Logger log = Logger.getLogger(AllocationBean.class);
    private Float allocations;
    private String importJobType;
    private long id;
    private long orgId;
}

public class ImportJobManagment implements Serializable
{
    private long importjobid;
    private long orgId;
    private String importJobType;
    private boolean allocations = false;
}

我已删除getter/setter为了简单起见。

更新:1的方式是建立正确的现在,我有一个表id列有外键引用ORGID和importJobType的复合键,我不知道我们是否能够做到这一点,有一个列外键到另一个组合键表,但是这是我的使用情况。

更新:2

谢谢你真棒细节,这肯定会enchance我的外键实现的知识,但我的最终目标是要一到两个表,其中表A具有识别该表和表B中唯一的行组合键之间的一个映射,我想有这将有外键引用表的主键一个这样的,如果我们在表格中的条目,则同样的jobId条目应在表B,现在我明白你的意思,我们不能有表B中单列主键,将参考在表A组合键

所以基本上我想有一个对表之间的一个映射,其中表A具有复合主键和表B具有使用休眠单个列主键,这是ofcourse我得到所提到的错误,因此现在我将创建在表复合键B还和现在做外键引用表A,我会核实并与我的调查结果更新我的问题后,查看详细的投入再次感谢。

Answer 1:

为自己的错误说,为了引用一个复合主键,则需要复合外键。 (你需要2个字段的唯一组合的复合主键状态使一个键 - 那么你不可能引用只有1列的唯一密钥。)

至于如何通过使用XML映射文件实现我不知道,大多数人使用的注释,这些天..

至于你的Java类,我假设ImportJobManagement持有ImportJob,所以后来的类不应引用的ID,但对象本身,就像这样:

public class ImportJobManagment implements Serializable {
    private ImportJob importJob;
    ...
}

Java类应该只是引用类的其他的,而不是在复合键成员 - 它是由映射到从复合关键Java成员变量映射。

答更新:

简短的回答是否定的,你不能。 外键的工作方式,它可以让你在引用表中的特定行。 而且,为了确保引用特定行,你需要一个身份,一些会描述只有一行,并没有其他。 在SQL没有实现这一点,即唯一键的构造。 通过规定一列(或列的组合)是唯一的,你知道它的/他们的总价值将是独一无二的,将有一个最大的1行的这个值对整个表,什么都将是一个约束冲突。

因此,外键是指单个唯一约束列或复合唯一键跨越多个列。 由于所有的表都有一个唯一的密钥已经,主键(这始终是唯一的),通常使用此为外键引用,但任何unqiue列会工作。

最简单的情况是,当我们想引用一个表单列唯一键。 两个简单的表A,持有一列“ID”,和B,其中持有“ID”列,而且另一列A_ID,其中有一个外键“ID” A的这方面的一个实例列情况可能是这样的:

A:
| id | 
|----|
|  1 |
|  2 |
|  3 |

B:
| id | a_id |
| 2  |  3   |
| 3  |  1   |

在此,在B参考各行中A.它的一个行的直接引用,在表B中A_ID值直接对应于A”的‘id’列中的值。 因此,与ID 2参考ID为3的A,等在B。

现在,让我们看看如何引用一个表有复合唯一键。 让我们保持我们的例子,但现在有另一列“sec_id”,这与“ID”共同构成一个复合主键。

A:
| id | sec_id |
|----|--------|
| 1  |   3    |
| 3  |   1    |
| 3  |   7    |

B:
| id | a_id |
|----|------|
| 2  |  3   |

在这种情况下,我们有一个自外键必须在它的引用,这显然行不通引用表中的一行B.一个问题。 这行中的确实值“3”代表什么? 第一行中的sec_id? 在id第二或第三(但是在这种情况下,哪一个?)? 答案当然是既不,没有足够的信息,在B到引用一个单行,所以SQL就不会拥有它。 增加这样一个外键因此不允许的。

为了使B到基准的,这将需要两个参考到A的“id'柱,和A的‘sec_id’列,因为在一个单排通过其唯一的(的组合来标识” ID”,‘sec_id’ )对。 因此,为B这样看:

| id | a_id | a_sec_id |
|----|------|----------|
| 1  |  1   |     3    |
| 2  |  3   |     1    |
| 3  |  3   |     7    |

现在,B保持足够的信息。在引用的单个行,并在将数据显示,它的作用。

再次更新:

目前,我正在阅读JPA认证,并已就复合键映射的章节。 为了映射复合主键,你需要它映射你的关键的属性的主键类。 有两种方法做的,其中一个关键属性还必须在实体本身映射,以及一个使用它的作为嵌入式密钥。

我提供的代码示例,他们很为自己说话(它的使用说明,你真正应该做的这一点。)

第一个例子是基座例如,与常规的ID级(未嵌入)。 在这里,我们在那里的主键是由一个整数ID以及一个国家的雇员实体(两名员工可以有相同的ID,如果在不同的国家)。

@Entity
@IdClass(EmployeeId.class)
public class Employee {
    @Id private String country
    @Id
    @Column(name = "EMP_ID")
    private int id;
    private String name;
    ...
}

public class EmployeeId implements Serializable {
    private String country;
    private int id;

    public EmployeeId() { }
    public EmployeeId(final String country, final int id) {
        this.country = country;
        this.id = id;
    }

    //getters for the properties

    public boolean equals(final Object other) {
    //must be implemented
    }

    public int hashCode() {
    //must be implemented
    }
}

注意:

  • 在类中的@ IdClass的注释。
  • 无论是ID-类的属性还必须在实体定义
  • 在ID类必须实现equals和hashCode

这是可以做到的另一种方式是通过嵌入式ID类:

@Entity
public class Employee {
    @EmbeddedId
    private EmployeeId id;
    private String name;

    public Employee(final String country, final int id) {
        this.id = new EmployeeId(country, id);
    }

    public String getCountry() {
        return id.getCountry();
    }
}   

@Embeddable
public class EmployeeId {
   private String country;
   @Column(name = "EMP_ID")
   private int id;

   //constructor + getters + equals +hashCode
}

注意:

  • 无需在实体定义的ID属性
  • 为了从实体的ID类的属性,你需要从ID级让他们

我喜欢,因为它更紧凑,后者更好,并且不包含重复的,但话又说回来,我不知道如何使用这两个比较..



Answer 2:

ImportJob.hbm.xml

使用此一个增加insert = false以importjobid像波纹管:

<property name="importjobid" type="long" 
    column="importjobid" type="long" insert="false"/>


文章来源: Hibernate Issue : Foreign key must have same number of columns as referenced primary key