Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the JPA specification allow references to non-primary key columns?

Does the JPA specification allow simple references to non-primary key columns?

I have a simple alternative/natural key (UNIQUE, NOT NULL) column iso_code on my Countries table which I'd like to use in a reference, but Eclipse's Dali shows a validation error and Hibernate throws a MappingException.

Is such a common scenario allowed?

like image 477
Kawu Avatar asked Apr 28 '11 12:04

Kawu


2 Answers

@axtavt: It appears as if your answer wasn't correct. I've just received an email from the authors of "Pro JPA 2.0", who were also working on the JPA spec themselves.

"In your example the Zip class has a relationship to a Country:

public class Zip implements Serializable
{
    @Id
    @Column(name = "code")
    private String code;

    @Id
    @ManyToOne
    @JoinColumn(name = "country_code", referencedColumnName = "iso_code")
    private Country country = null;
    ...
}

This appears to be trying to point the country_code foreign key column to the iso_code column in the Country table, which is not a PK. JPA has never allowed you to create a relationship like this because without specifying the PK of the Country there would be no way to uniquely identify which Country instance is in the relationship. You are simply hitting the problem when you get to the derived identifier part, but the problem looks to be in the invalid relationship itself."

So the JPA spec doesn't allow relationships/FKs to non-PK columns at all...

like image 101
Kawu Avatar answered Oct 18 '22 15:10

Kawu


Support of relationships that references non-PK columns is an optional feature. In simple cases it's supported by Hibernate, but it can't be used as a part of dervied identity.

However, as long as you don't derive an identity (i.e. if you can set a value of primary key component manually) you can try to play with read-only mappings, something like this:

@Entity
@Table(name = "Zips")
@IdClass(value = ZipId.class)
public class Zip implements Serializable
{
    @Id
    @Column(name = "code")
    private String code;

    @Id
    @Column(name = "country_code")
    private String countryCode; // Primary key component should be set manually

    @ManyToOne
    @JoinColumn(name = "country_code", referencedColumnName = "iso_code", 
        insertable = false, updatable = false)
    private Country country = null; // Read-only relationship based on a value 
                                    // of primary key component

    ...
}
like image 40
axtavt Avatar answered Oct 18 '22 13:10

axtavt