• Skip to primary navigation
  • Skip to content
  • Skip to primary sidebar

Thoughts on Java

  • Tutorials ▼
    • Hibernate & JPA Tutorials
    • Hibernate Tips
    • Tutorials on YouTube
  • Books & Training ▼
    • Hibernate Tips Book
    • Online Training
    • On-Site Training
  • Consulting ▼
    • Consulting Call
    • Project Coaching
  • About ▼
    • About Thoughts on Java
    • Support Thoughts on Java
    • Resources
  • Member Library
You are here: Home / Hibernate / Hibernate Advanced / How to persist additional attributes for a relationship with JPA and Hibernate
Special thanks to all Thoughts on Java Supporters for supporting this article!

How to persist additional attributes for a relationship with JPA and Hibernate

By Thorben Janssen 3 Comments

  • tweet 
  • share 
  • share 
  • share 
  • share 
  • share 
  • e-mail 


JPA and Hibernate allow you to define relationships between entities with just a few annotations, and you don’t have to care about the underlying table model in the database. Even join tables for many-to-many relationships are hidden behind a @JoinTable annotation, and you don’t need to model the additional table as an entity.

That changes as soon as you have to persist additional attributes for a relationship. The obvious way to handle them is to create an entity for the join table and add the attribute there. But that sounds easier as it is. As you will see, there are several things you need to take care of to model it correctly.


Already a member? Login here.

Model

You know the example for this post from a typical bookstore. There are books in multiple formats (e.g. hardcover, paperback, ebook) and each format was published by a different publisher.

You can modeled with 3 entities, which you can see in the following diagram. The Book and Publisher entity are pretty obvious and model the two main domain objects. The third one is the BookPublisher entity which models the relationship between the Book and the Publisher and keeps the Format as an additional attribute.

class diagram

OK, if you have some experience with database modelling, you probably expected such an entity model. It is pretty close to the database model and not too difficult. The tricky part is to define the BookPublisher entity in a way that allows you easy read and write access and assures referential integrity at all time. But before we get into that, let’s have a quick look at the Book and Publisher entities.

 

The Book and Publisher entities

There is nothing too interesting about the Book and the Publisher entity. Both of them define a one-to-many relationship to the BookPublisher entity. The interesting parts of the mapping are in the BookPublisher entity which I will show you in the next section.

The BookPublisher entity

OK, I promised you that the mapping of the BookPublisher entity is more interesting than the ones I showed you before. And I intend to keep that promise.

As you have seen in the diagram, the BookPublisher entity maps the relationship between the Book and the Publisher entities and stores the format of the book as an additional attribute. At the first look, the required mapping might seem easy. You only need 2 many-to-one relationships and the additional attribute.

So how can you use
the same database column
for two mappings?

But what about the primary key? As you have seen in the diagram, the BookPublisher entity uses the combination of the foreign key of the Book entity and the foreign key of the Publisher entity as the primary key. Both of them are also mapped by the many-to-one relationships. So how can you use the same database column for two mappings? And what do you need to do to keep them in sync?

Let’s have a look at the primary key first. As you can see in the following code snippet, I define the inner class BookPublisherId and annotate it with @Embeddable so that I can use it later on as an embedded id.
The mapping of the BookPublisherId is quite simple. You just need to annotate the two attributes with a @Column annotation. But there are a few other things you need to take care of if you want to use an embeddable object as a primary key. Your class needs to implement the Serializable interface, and you need to implement the hashCode and equals methods. OK, that’s all for the primary key class. Let’s have a look at the BookPublisher mapping.


Already a member? Login here.


As you can see in the code snippet, the id attribute is of type BookPublisherId, and I annotated it with @EmbeddedId. That tells Hibernate to use the BookPublisherId class as the primary class and use its mapping definition to map the attributes to the database columns.

The important part
for these mappings
are the propertie
sinsertable and updatable
which Hibernate requires you
to set to false …

In the following lines, you can see the mapping definition of the 2 many-to-one relationships to the Book and Publisher entities. The important part for these mappings are the properties insertable and updatable which Hibernate requires you to set to false because the database columns fk_book and fk_publisher are already used in the mapping of the BookPublisherId class.

If the relationship mappings can’t be changed, you obviously need to initialize them in the BookPublisher constructor. As you can see in the code snippet, the constructor expects a Book and a Publisher entity and a Format enum value. These are used to create a new instance of the BookPublisherId class as the primary key, to initialize the relationship to the Book and Publisher entity and to set the format attribute. And you also need to add the new BookPublisher entity to the relationships of the Book and Publisher entity.

That’s all you need to do to define the mapping, and you can now use it in your application.

How to use the mapping

You can use the BookPublisher entity in the same way as any other entity. The only thing you need to keep in mind is that you need to persist the Book and the Publisher entity so that their primary key gets initialized before you can instantiate a BookPublisher entity for them.

Summary and cheat sheet

As you have seen, you need to define an entity for the relationship table to map to-many relationships with additional attributes. You can use the foreign key columns of the related entities as the primary key of the relationship entity. And you can also use them to map the relationships and provide a comfortable way to navigate the relationship. But Hibernate then requires you to set the insertable and updatable properties of the relationship mappings to false to make them immutable.


Already a member? Login here.

  • tweet 
  • share 
  • share 
  • share 
  • share 
  • share 
  • e-mail 

Related posts:

  1. How to map an association as a java.util.Map
  2. Ordering vs Sorting with Hibernate – What should you use?
  3. Why you should avoid CascadeType.REMOVE for to-many associations and what to do instead
  4. Best Practices for Many-To-One and One-To-Many Association Mappings
Become a Thoughts on Java Supporter to claim your member perks and to help me write more articles like this.

Filed Under: Hibernate Advanced, JPA Tagged With: Association Mapping, Mapping

Implement Your Persistence Layer with Ease

Learn More About Hibernate

Need Some Help with Your Project?

Reader Interactions

Comments

  1. Arun Menon says

    June 1, 2016 at 7:54 am

    Thanks !!!! As always Nice and concise explanation. On a totally unrelated note, when I was implementing the code that you have given in the article I cant help noticing how tough it is to actually set up a simple maven-jpa-hibernate-h2 DB setup(Knowing the dependencies and their version). I decided to go ahead and use spring boot as it is much faster and then ran into trouble with transactions. Since I am using eclipse I believe the only work around will be to create a template POM and keep reusing that.

    Reply
  2. Al Grant says

    August 15, 2017 at 10:15 am

    Did you intend to have two BookPublisher classes in seperate files?

    Reply
    • Thorben Janssen says

      September 4, 2017 at 6:27 am

      No, that’s just because I wanted to split the code into 2 snippets. Both code snippets should be in the same file.

      Reply

Leave a Reply Cancel 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.

Primary Sidebar

Join over 10.000 developers
in the
Thoughts on Java Library

Ebooks Sidebar Get free access to ebooks, cheat sheets and training videos.
Join Now!
Don't like ads?
Become a Thoughts on Java Supporter.
Special Launch Price

Let’s Connect


Thorben Janssen
Independent consultant, trainer and author
  • Facebook
  • GitHub
  • Google+
  • LinkedIn
  • Twitter
  • xing
  • YouTube

Speaking at

7th February 2019
JUG Ostfalen (Germany):
Hibernate Tips 'n' Tricks: Typische Probleme schnell gelöst (Talk - German)

19th March 2019
JavaLand 2019 (Germany):
Hibernate Tips 'n' Tricks: Typische Probleme schnell gelöst (Talk - German)

21st March 2019
JavaLand 2019 (Germany):
Hibernate + jOOQ + Flyway = Die besten Frameworks in einem Stack (1-day Workshop - German)

6th-10th May 2019
JAX 2019 (Germany):
Hibernate Workshop: Komplexe Lösungen jenseits von CRUD (2-day Workshop - German)

6th-10th May 2019
JAX 2019 (Germany):
Spring Data JDBC vs. Spring Data JPA – Wer macht das Rennen? (Talk - German)

6th-10th May 2019
JAX 2019 (Germany):
Microservices mit Hibernate – typische Probleme und Lösungen (Talk - German)

Looking for an on-site training?

Featured Post

14 YouTube Channels You Should Follow in 2019

Getting Started With Hibernate

Entities or DTOs – When should you use which projection?

Ultimate Guide – Association Mappings with JPA and Hibernate

Ultimate Guide to JPQL Queries with JPA and Hibernate

Recent Posts

  • Hibernate Tips: How to Customize a Constructor Expression for Different Subclasses
  • Hibernate Tips: How to Map java.time.Year with JPA and Hibernate
  • Why, When and How to Use DTO Projections with JPA and Hibernate
  • Hibernate Tip: Map a bidirectional one-to-one association with shared composite primary key
  • Implementing the Repository pattern with JPA and Hibernate
  • Hibernate Tips: How to Handle NULL Values while Ordering Query Results in a CriteriaQuery
  • 6 Hibernate Best Practices for Readable and Maintainable Code
  • Can you use Hibernate/EclipseLink/JPA for your microservice?
  • 14 YouTube Channels You Should Follow in 2019
  • Hibernate Tips: How To Map an Entity to a Query
Don't like ads?
Become a Thoughts on Java Supporter.

Copyright © 2019 Thoughts on Java

  • Impressum
  • Disclaimer
  • Privacy Policy