How to reference a parent association using @JoinColumns without referencing the parent identifier with JPA and Hibernate


#1

Hi,
I receive some stacktrace during startup after modelling my entities:
org.hibernate.MappingException: invalid join columns for association: provider.debtor

The simplified model is

@Entity
public class Debtor {
...
	private Provider provider;
	@OneToOne(fetch = LAZY)
	@JoinColumns({@JoinColumn(name = "provider_id", referencedColumnName = "outer_provider_id"),
			@JoinColumn(name = "location", referencedColumnName = "location")})
	public Provider getProvider() {
		return provider;
	}
}

@Entity
public class Provider {
...
	private Debtor debtor;
	@OneToOne(mappedBy = "provider")
	public Debtor getDebtor() {
		return debtor;
	}
}

There are other Entities having a Provider relationship - functional - with the same join columns definition, but they are all ManyToOne. Is there a rule unknown to me about using JoinColumns with OneToOne?

I debugged Hibernate and it seems to have a problem resolving the join at:

validateJoin:180, OuterJoinableAssociation (org.hibernate.loader)
addAssociationToJoinTree:240, JoinWalker (org.hibernate.loader)
addAssociationToJoinTreeIfNecessary:187, JoinWalker (org.hibernate.loader)
walkEntityAssociationTree:401, JoinWalker (org.hibernate.loader)
walkEntityTree:515, JoinWalker (org.hibernate.loader)
...

and this is the stack content at the time:

this = {OuterJoinableAssociation@9119} 
path = "provider.debtor"
lhsColumns = {String[1]@9122} 
 0 = "provider1_.provider_id"
rhsColumns = {String[2]@9123} 
 0 = "provider_id"
 1 = "location"

#2

The problem might be caused because the Provider entity has a single-column identifier (e.g. provider_id) while you try to reference this entity by 2 columns (e.g. provider_id and location).

Since the provider_id is unique, why do you want to add the extra column to locate the Provider from the Debtor entity?

If you want to reference the @OneToOne association by a non-identifier parent property or combination of properties, you can use @JoinFormula.


#3

Not quite, the table PROVIDER has a primary key, but in the entity relationship diagram it is not used as the foreign key, instead the people before me (may they roast in a very special hell for IT abuse) have used two other columns as a natural key to link the tables. The database is certainly older than Hibernate and JDBC and they had a concept that all database access had to be done through stored procedure calls.

Anyway, almost all relations to the provider table use two columns as foreign key, none of which is the primary key.
In the ManyToOne relationships this works in JPA/Hibernate, but the OneToOneType seems to be hardcoded to use the PK as LHS join, not any JoinTable annotation.


#4

I think it’s not currently possible to reference an association without using the identifier. So, if the @JoinColumns don’t match the parent identifier, then relationship will not work unless adding support for it in Hibernate.

Would you like to investigate it and provide a Pull Request with a fix proposal?


#5

I have still one pull request open (https://github.com/hibernate/hibernate-orm/pull/2666) that sadly broke a few tests that I had no time to investigate (and to be honest, I am not yet common enough with the whole source repository)
I made a workaround and use a entity manager query now to get to the object, so I am no longer in an urgent need, but if you like to investigate, the crucial line causing the trouble is here:
https://github.com/hibernate/hibernate-orm/blob/3218f6cc7df4f704eef5d70cc3514856e7d6f56d/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java#L186


#6

I think it’s best to try to fix this in 6.0 since the API has changed significantly. Once we get a release candidate, we can further investigate it.