Hibernation problem: a foreign key must have the same number of columns as a reference primary key

Purpose: I want to have importJobId in ImportJob as a foreign key for the identifier of the distribution table, so when we have importJobId, then and only then we can have the identifier in the distribution, since there can be no distributions without Job.

The ImportJob table has a composite primary key like [ORGID, IMPORTJOBTYPE], and I'm trying to get the foreign key relation in hibernate using

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

in Allocation.hbm.xml, which does not work and an error message appears:

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

Here is my ImportJob.hbm.xml file

  <?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> 

Below are the bean classes for reference:

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

I removed getter/setter for simplicity.

Update: 1 The way it is configured right now, I have an id column in one table that has a foreign key reference for the composite key orgId and importJobType, not sure if we can do this and have one column that would be included into the composite key of another table, but my use case.

Update: 2

Thanks for the amazing details, this will certainly interest my knowledge of foreign key implementation, but my ultimate goal is to compare between two tables with each other, where table A contains a composite key to identify a unique row in this table and table B. I want to have a primary a key that will have a link to a foreign key for table A, so if we have an entry in table A, then the same jobId entry should be in table B, now I get your point that we cannot have a primary key of one col ki in table B which will refer to the composite key in table A.

so basically I want to have a one-to-one mapping between tables in which table A has a composite primary key and table B has one column primary key using hibernate, which unfortunately causes the specified error, and so now I'm going to create the composite keys in table B also now refer to an external link to table A, I will check and update my question with my findings later, thanks again for the detailed information.

+4
source share
2 answers

The error speaks for itself, to refer to a composite primary key, you need a complex foreign key. (The composite primary key indicates that you need a unique combination of 2 fields to create a key - then you cannot refer to a unique key in just 1 column.)

As for how this is achieved using xml mapping files, I'm not sure most people use annotations these days.

As for your Java classes, I assume that ImportJobManagement contains ImportJob, so the class should not refer to id, but the object itself, for example:

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

Java classes should simply refer to another class, and not to the constituent parts of the composite key - this is a mapping to the mapping from the composite key to a Java member variable.

Response to update:

The short answer is no, you cannot. How a foreign key works, it allows you to refer to a specific row in the table. And, of course, to refer to a specific line, you need a personality to describe only one line and the other. There is a construct in SQL to achieve this, namely a unique key. By stating that a column (or composite column) is unique, you know that its / their combined value will be unique, there will be a maximum of 1 row in the whole table in the whole table, everything else will be in violation of the restriction.

Thus, a foreign key refers to either a single column with a unique constraint or a composite unique key spanning multiple columns. Since all tables already have a unique key, the primary key (which is always unique) is usually used to refer to foreign keys, but any unqiue column will work.

The simplest case is when we want to refer to a table with a unique key with one column. Two simple tables A, which contain one column "id" and B, which contains the column "id", but also another column a_id, which has a foreign key in the column "id" for A. An example of this situation could be this:

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

Here, each row in B refers to a row in A. Its direct link, the value in a_id in table B corresponds directly to the value in column A '' id '. So B with id 2 refers to A with id 3, etc.

Now let's see how to reference a table with a composite unique key. Let's save our example, but now A has another column "sec_id", which together with "id" constitutes a composite primary key.

 A: | id | sec_id | |----|--------| | 1 | 3 | | 3 | 1 | | 3 | 7 | B: | id | a_id | |----|------| | 2 | 3 | 

In this situation, we have a problem in B. Since the foreign key must refer to one row in the table, referring to it, this obviously does not work. Which line in represents the value "3"? Sec_id on the first line? The identifier in the second or third (but in this case, which?)? The answer, of course, is not that there is not enough information in B to refer to a single row in A, so there will simply be no SQL. Therefore, adding such a foreign key is not allowed.

In order for B to refer to A, it will require both a reference to the column A 'id'-column and A' sec_id ', since one row in is identified by its unique combination (' id ',' sec_id '). So with B it looks like this:

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

Now B contains enough information to refer to a single line in A, and as the data shows, it does.

Refresh again:

I am currently reading for JPA certification and have reached the chapter on composite key mappings. To display a composite primary key, you need a primary key class that displays the attributes of your key. There are two ways to do this: the one where the key attribute should also appear in the entity itself and the one where it was used as a built-in key.

I will give code examples, they just speak for themselves (using annotations, you really have to do this).

The first example is a basic example with a regular id class (not built-in). Here we have an Employee object, where the primary key consists of an integer identifier and a country (two employees can have the same identifier, if in different countries).

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

Note:

  • @IdClass annotations for the class.
  • Both id class attributes must also be defined in essence
  • id class should implement equals and hashcode

In another way, this can be done through the built-in id class:

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

Note:

  • No need to define id attributes in entity
  • To get id class attributes from an entity, you need to get them from the id class

I like the latter better because it is more compact and does not contain duplication, but again I do not know how to use these two comparisons.

+10
source

ImportJob.hbm.xml

with this, add insert = false in the importjobid, as shown below:

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

All Articles