|

Hibernate Tips: How to model an association that doesn’t reference primary key columns


Take your skills to the next level!

The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.


Hibernate Tips is a series of posts in which I describe a quick and easy solution for common Hibernate questions. If you have a question for a future Hibernate Tip, please leave a comment below.

Question:

I have to map a legacy table model with Hibernate. It contains a many-to-one association that uses a non-primary key column on the to-one side. Is there any way to map that with Hibernate?

Solution:

Yes, you can reference any column in your association mapping, that contains unique values, e.g., a natural id. You just need an additional @JoinColumn annotation to tell Hibernate which column it shall use.

Let’s adapt my usual bookstore example. It consists of a Book and a Review entity. Each Review belongs to one Book, and each Book might have been reviewed multiple times.

That is a typical one-to-many association. When you create the table model, you normally use the primary key column id of the book table as the foreign key in the review table. But in this example, I want to use the isbn of the Book instead.

You typically define a one-to-many association with a @ManyToOne annotation on the entity that models the to-many site. So, in this case, on the Review entity. The usage of the isbn as the foreign key requires an additional @JoinColumn annotation. The referencedColumnName attribute tells Hibernate the name of the database column it shall use as the foreign key.

@Entity
public class Review {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;

	@ManyToOne
	@JoinColumn(referencedColumnName = "isbn")
	private Book book;
	
	...
}

There is one small thing left before you can use this association. You need to make sure, that the referenced entity implements Serializable. And you might consider annotating the isbn attribute with @NaturalId so that you can use Hibernate’s proprietary natural identifier features.

@Entity
public class Book implements Serializable {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;

	@NaturalId
	private String isbn;
	
	@OneToMany(mappedBy = "book")
	private List<Review> reviews = new ArrayList<Review>();
	
	...
}

Learn more:

Most table models use the primary key of one table as the foreign key in an associated table. These mappings are easier to define, but there are still a few things you should know about. You can learn more about them in my association mapping guide.

And if you’re just looking for a few best practices, take a look at this post: Best Practices for Many-To-One and One-To-Many Association Mappings.

Hibernate Tips Book

Get more recipes like this one in my new book Hibernate Tips: More than 70 solutions to common Hibernate problems.

It gives you more than 70 ready-to-use recipes for topics like basic and advanced mappings, logging, Java 8 support, caching, and statically and dynamically defined queries.

Get it now!