Thoughts on Java

  • Blog
    • Hibernate & JPA Tutorials
    • Hibernate Tips
  • Videos
  • Book
  • Training
  • Work with me
  • About
    • About Thoughts on Java
    • Resources
  • Member Library
You are here: Home / Hibernate / Hibernate Tips: How to map an entity to multiple tables

Hibernate Tips: How to map an entity to multiple tables

April 17, 2018 By Thorben Janssen 2 Comments

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’m working with a legacy database, and I need to map an entity to 2 database tables. Is there any way to do that with JPA or Hibernate?


 

Solution:

Yes, you can map an entity to 2 database tables in 2 simple steps:

  1. You need to annotate your entity with JPA’s @Table and @SecondaryTable annotations and provide the names of the first and second table as the value of the name parameters.
  2. You need to annotate each attribute which you want to map to the secondary table with a @Column annotation and set the name of the secondary table as the value of the table attribute.

Map the Author entity to 2 tables

Let’s take a look at a simple example that maps the author and the author_details table to the Author entity. Here are the 2 tables:

The following code maps these tables to the Author entity.

The @Table annotation defines the primary table to which the entity attributes get mapped by default. In this example, that’s the case for the id, version, firstName, and lastName attributes.

The @SecondaryTable annotation specifies the second database table to which the entity gets mapped. It consists of the columns id, pseudonym, and category. You need to annotate the attributes that map these columns with an additional @Column annotation that provides the name of the secondary table.

@Entity
@Table(name = "author")
@SecondaryTable(name = "author_details")
public class Author {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(updatable = false, nullable = false)
	private Long id;

	@Version
	private int version;

	private String firstName;

	private String lastName;

	@Column(table = "author_details")
	private String pseudonym;

	@Column(table = "author_details")
	private Category category;

	...
}

That’s all you need to do to map the 2 database tables to the Author entity. Every time you persist or update an Author entity, Hibernate writes the values of the id, firstName, lastName, and version attributes to the author table, and the values of the id, pseudonym, and category attributes to the author_details table.

And when you read an Author entity, Hibernate gets the attribute values from the same 2 tables.

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

Author a = new Author();
a.setFirstName("Thorben");
a.setLastName("Janssen");
a.setCategory(Category.NON_FICTION);
a.setPseudonym("Thorben Janssen");
em.persist(a);

em.getTransaction().commit();
em.close();

As you can see in the log output, Hibernate uses the name and value of the primary key column of the primary table also as the name and value of the primary key column of the secondary table.

09:12:40,154 DEBUG [org.hibernate.SQL] - 
    select
        nextval ('hibernate_sequence')
09:12:40,204 DEBUG [org.hibernate.SQL] - 
    insert 
    into
        author
        (firstName, lastName, version, id) 
    values
        (?, ?, ?, ?)
09:12:40,218 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [1] as [VARCHAR] - [Thorben]
09:12:40,218 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [2] as [VARCHAR] - [Janssen]
09:12:40,219 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [3] as [INTEGER] - [0]
09:12:40,222 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [4] as [BIGINT] - [1]
09:12:40,225 DEBUG [org.hibernate.SQL] - 
    insert 
    into
        author_details
        (category, pseudonym, id) 
    values
        (?, ?, ?)
09:12:40,225 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [2] as [VARCHAR] - [Thorben Janssen]
09:12:40,226 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [3] as [BIGINT] - [1]

 

Customize the primary key columns

The previous example didn’t specify the name of the primary key column in the secondary table. By default, Hibernate uses an identical mapping to map the primary key attribute to both tables. If you’re working with a legacy database, you might need to adapt this for the secondary table.

You can do that with the pkJoinColumns attribute of the @SecondaryTable annotation. It allows you to customize the mapping with one or more @PrimaryKeyJoinColumn annotations. Its name attribute specifies the name of the primary key column of the secondary table and the referencedColumnName attribute defines the name of the primary key column of the primary table.

@Entity
@Table(name = "author")
@SecondaryTable(name = "author_details", pkJoinColumns = @PrimaryKeyJoinColumn(name = "authorId", referencedColumnName = "id"))
public class Author { ... }

When you now persist a new Author entity, Hibernate uses the authorId column as the primary key column of the author_details table.

09:13:34,254 DEBUG [org.hibernate.SQL] - 
    select
        nextval ('hibernate_sequence')
09:13:34,315 DEBUG [org.hibernate.SQL] - 
    insert 
    into
        author
        (firstName, lastName, version, id) 
    values
        (?, ?, ?, ?)
09:13:34,321 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [1] as [VARCHAR] - [Thorben]
09:13:34,323 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [2] as [VARCHAR] - [Janssen]
09:13:34,324 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [3] as [INTEGER] - [0]
09:13:34,327 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [4] as [BIGINT] - [1]
09:13:34,330 DEBUG [org.hibernate.SQL] - 
    insert 
    into
        author_details
        (category, pseudonym, authorId) 
    values
        (?, ?, ?)
09:13:34,331 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [2] as [VARCHAR] - [Thorben Janssen]
09:13:34,331 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [3] as [BIGINT] - [1]

Get this Hibernate Tip as a printable PDF!

Join the free Thoughts on Java Library to get access to lots of member-only content, like a printable PDF for this post, lots of cheat sheets and 2 ebooks about Hibernate.
Join Now!

Already a member? Login here.

Learn more:

If you enjoyed this post, you might also be interested in the following posts about entity mappings:

  • Hibernate Tips: How to Map Multiple Entities to the Same Table
  • Hibernate Tips: How to escape table and column names
  • Hibernate Tips: How to define schema and table names
 

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 as a paperback, ebook or PDF.

Related posts:

  1. Hibernate Tips: How to delete child entities from a many-to-one association
  2. Hibernate Tips: How to Map Multiple Entities to the Same Table
  3. Hibernate Tips: How to use an ORDER BY clause in a CriteriaQuery
  4. Hibernate Tips: How to avoid Hibernate’s MultipleBagFetchException

Filed Under: Hibernate, JPA, Tips

Implement Your Persistence Layer with Ease

Learn More About Hibernate

Need Some Help with Your Project?

Comments

  1. Puspender says

    April 19, 2018 at 10:10 pm

    Nice article Thorben.

    Reply
    • Thorben Janssen says

      April 21, 2018 at 2:47 pm

      Thanks

      Reply

Leave a Reply Cancel reply

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

Join over 5.000 developers
in the
Thoughts on Java Library

Ebooks Sidebar Get free access to ebooks, cheat sheets and training videos.
Join Now!
Special Launch Price

Let’s Connect


Thorben Janssen
  • Facebook
  • Github
  • Google+
  • Twitter
  • YouTube

Speaking at

8th March 2018
Voxxed Days Zurich (Talk):
Hibernate Tips ‘n’ Tricks - 15 Tips to solve common problems

13th March 2018
JavaLand (Talk):
Hibernate - State of the Union

15th March 2018
JavaLand (Workshop):
Hibernate Performance Tuning

10th-11th April 2018
Munich (Training):
Hibernate für Fortgeschrittene

12th-13th April 2018
Munich (Training):
Hibernate Performance Tuning

April 2018
JAX (Talk):
Hibernate Tipps und Tricks: Schnelle Lösungen für typische Probleme und Anwendungsfälle

April 2018
JAX (Workshop):
Hibernate-Workshop für Fortgeschrittene

Looking for an inhouse training?

Featured Post

Getting Started With Hibernate

Getting Started With Hibernate

12 Java YouTube Channels You Should Follow In 2018

12 Java YouTube Channels You Should Follow In 2018

Ultimate Guide – Association Mappings with JPA and Hibernate

Ultimate Guide – Association Mappings with JPA and Hibernate

Ultimate Guide to JPQL Queries with JPA and Hibernate

Ultimate Guide to JPQL Queries with JPA and Hibernate

Hibernate Best Practices

Hibernate Best Practices

Recent Posts

  • 5 Common Hibernate Mistakes That Cause Dozens of Unexpected Queries
  • Hibernate Tips: How to map an entity to multiple tables
  • Hibernate Tips: Easiest way to manage bi-directional associations
  • Hibernate & jOOQ – A Match Made in Heaven
  • Hibernate Tips: How to avoid Hibernate’s MultipleBagFetchException
  • Getting Started with jOOQ – Building SQL Queries in Java
  • Composition vs. Inheritance with JPA and Hibernate
  • JPA Tips: How to map a Duration attribute
  • Hibernate Tips: How to use an ORDER BY clause in a CriteriaQuery
  • What’s the difference between JPA, Hibernate and EclipseLink

Copyright © 2018 · Thoughts on Java

  • Impressum
  • Disclaimer
  • Privacy Policy
Thoughts on Java