How do I create a ToOne relationship to an entity where the referenced column name is on a secondary table?

How do I create a xxxToOne relationship to an entity, where the referenced column name of the JoinColumn annotation is on a secondary table?
I debugged org.hibernate.cfg.BinderHelper and it looks like it is only checking the physical table, I think that means the primary table of the entity, although the error message is

org.hibernate.MappingException: Unable to find column with logical name: foreign_key_id in org.hibernate.mapping.Table(JoinedEntity) and its related supertables and secondary tables

This is a bit of pseudo code to describe the problem:

@Entity @Inheritance(strategy = JOINED)
@DiscriminatorColumn(name = "type_code")
@Table(name = "master_table", schema = "dbo")
public abstract class Master{
    private Long id;
    @Id
    @Column(name = "id")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

@Entity
@DiscriminatorValue("3")
@SecondaryTable(name = "MORE_FIELDS", schema = "dbo", pkJoinColumns = @PrimaryKeyJoinColumn(name = "more_fields_id"))
public class MoreFields extends Master {
    private Long foreignKeyId;
	@Basic
	@Column(name = "foreign_key_id", table = "MORE_FIELDS")
	public Long getForeignKeyId() {
		return foreignKeyId;
	}

	public void setForeignKeyId(Long foreignKeyId) {
		this.foreignKeyId= foreignKeyId;
	}

}

@Entity
@Table(name = "FOREIGN_KEY_HOLDER", schema = "dbo")
public class ForeignKeyHolder {
    private MoreFields  moreFields;

    @ManyToOne
    @JoinColumn(name = "more_fields_id", referencedColumnName = "foreign_key_id")
    public Provider getMoreFields() {
        return moreFields;
    }

}

  1. You don’t need the @SecondaryTable annotation in a JOINED inheritance strategy since all the properties in the subclass entity (e.g. MoreFields) go to the subclass-specific table as well.

  2. Also, you don’t need to map the foreignKeyId unless you use insertable and updatable to false since you’d have two properties managing the same DB column.

  3. You need to use the PrimaryKeyJoinColumn if you want to customize the PK column name in the subclass-specific table.

     @PrimaryKeyJoinColumn(name = "more_fields_id")
    

Therefore, your mapping becomes:

@Entity @Inheritance(strategy = JOINED)
@DiscriminatorColumn(name = "type_code")
@Table(name = "master_table", schema = "dbo")
public abstract class Master{
    private Long id;
    @Id
    @Column(name = "id")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

@Entity
@DiscriminatorValue("3")
@Table(name = "MORE_FIELDS", schema = "dbo")
@PrimaryKeyJoinColumn(name = "more_fields_id")
public class MoreFields extends Master {

}

@Entity
@Table(name = "FOREIGN_KEY_HOLDER", schema = "dbo")
public class ForeignKeyHolder {
    private MoreFields  moreFields;

    @ManyToOne
    @JoinColumn(name = "more_fields_id", referencedColumnName = "more_fields_id")
    public MoreFields getMoreFields() {
        return moreFields;
    }

}

More, there is no reason to create an abstract base table with JOINED inheritance. It looks like @MappedSuperclass is more suitable for the Master class.

1 Like