How to map a @ManyToOne association using a non-Primary Key column with JPA and Hibernate

(Last Updated On: January 4, 2018)


While answering questions on the Hibernate forum, I stumbled on the following question about using the @ManyToOne annotation when the Foreign Key column on the client side references a non-Primary Key column on the parent side.

In this article, you are going to see how to use the @JoinColumn annotation in order to accommodate non-Primary Key many-to-one associations.

Domain Model

Assuming we have the following tables in our database:

The isbn column on the publication and book tables are linked via a Foreign Key constraint which is the base of our @ManyToOne assocation:

Non Primary-Key @ManyToOne mapping

The Book represents the parent side of the association, and it’s mapped as follows:

@Entity(name = "Book")
@Table(name = "book")
public static class Book 
    implements Serializable {

    private Long id;

    private String title;

    private String author;

    private String isbn;

    //Getters and setters omitted for brevity

The isbn column is mapped as a @NaturalId since it can be used as a business key as well.

For more details about the @NaturalId annotation, check out this article.

The Publication represents the child of the association, so it’s going to be mapped like this:

@Entity(name = "Publication")
@Table(name = "publication")
public static class Publication {

    private Long id;

    private String publisher;

    @ManyToOne(fetch = FetchType.LAZY)
        name = "isbn", 
        referencedColumnName = "isbn"
    private Book book;

        name = "price_in_cents", 
        nullable = false
    private Integer priceCents;

    private String currency;

    //Getters and setters omitted for brevity

By default, the @ManyToOne association assumes that the parent-side entity identifier is to be used to join with the client-side entity Foreign Key column.

However, when using a non-Primary Key association, the referencedColumnName should be used to instruct Hibernate which column should be used on the parent side to establish the many-to-one database relationship.

Testing time

Assuming we have the following entities in our database:

Book book = new Book();
book.setTitle( "High-Performance Java Persistence" );
book.setAuthor( "Vlad Mihalcea" );
book.setIsbn( "978-9730228236" );

Publication amazonUs = new Publication();
amazonUs.setPublisher( "" );
amazonUs.setBook( book );
amazonUs.setPriceCents( 4599 );
amazonUs.setCurrency( "$" );
entityManager.persist( amazonUs );

Publication amazonUk = new Publication();
amazonUk.setPublisher( "" );
amazonUk.setBook( book );
amazonUk.setPriceCents( 3545 );
amazonUk.setCurrency( "&" );
entityManager.persist( amazonUk );

Upon fetching the Publication along with its associated Book, we can see that the @ManyToOne association works as expected:

Publication publication = entityManager.createQuery(
    "select p " +
    "from Publication p " +
    "join fetch b " +
    "where " +
    "   b.isbn = :isbn and " +
    "   p.currency = :currency", Publication.class)
.setParameter( "isbn", "978-9730228236" )
.setParameter( "currency", "&" )


    "High-Performance Java Persistence",

When executing the JPQL query above, Hibernate generates the following SQL statement:

SELECT AS id1_1_0_, AS id1_0_1_,
        p.isbn AS isbn5_1_0_, p.currency AS currency2_1_0_,
        p.price_in_cents AS price_in3_1_0_,
        p.publisher AS publishe4_1_0_, AS author2_0_1_, b.isbn AS isbn3_0_1_,
        b.title AS title4_0_1_
FROM    publication p
        book b ON p.isbn = b.isbn
WHERE   b.isbn = '978-9730228236'
        AND p.currency = '&'

As you can see, the referencedColumnName allows you to customize the JOIN ON clause so that the isbn column is used instead of the default entity identifier.

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.


If you want to represent a non-Primary Key @ManyToOne association, you should use the referencedColumnName attribute of the @JoinColumn annotation.

For more complex situations, like when you need to use a custom SQL function in the JOIN ON clause, you can use the Hibernate specific @JoinFormula annotation.

Subscribe to our Newsletter

* indicates required
10 000 readers have found this blog worth following!

If you subscribe to my newsletter, you'll get:
  • A free sample of my Video Course about running Integration tests at warp-speed using Docker and tmpfs
  • 3 chapters from my book, High-Performance Java Persistence, 
  • a 10% discount coupon for my book. 
Get the most out of your persistence layer!


6 thoughts on “How to map a @ManyToOne association using a non-Primary Key column with JPA and Hibernate

  1. I don’t know if my previous comment came through, but I solved it. I forgot to define the referencedColumnName which is crucial for this.
    I left it out as it was the same as the name itself. But apparently referencedColumnName is needed 🙂

  2. Hi Vlad, nice article!

    Does it support multiple @JoinColumn’s?

    I have a Foreign Key towards a non-Primary Key and it contains 3 columns.
    I used @ManyToOne with @JoinColumns({ .. }) with the 3 columns, but Hibernate throws an exception:
    Caused by: org.hibernate.AnnotationException: A Foreign key refering com.mycomp.model.SomeEntity from com.mycomp.model.SomeOtherEntity has the wrong number of column. should be 1

    I have the feeling that it tries to hookup my Foreign Key to the Primary Key of the reference table.
    In your example I see no explicit definition to hoo it up towards a unique key, so I guess that is not needed.

  3. Hello. I just used this example with my application and I received an error.

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’ defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Repeated column in mapping for entity: com.asyncexample.model.Taglocation column: rfidtag (should be mapped with insert=”false” update=”false”)

    Should I add the insert and update? I’m using mysql and Spring boot with Eclipse. Thanks!

    1. Yes, you should because you mapped both the FK column and added the association as well which uses the same FK.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.