DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Architecture and Code Design, Pt. 1: Relational Persistence Insights to Use Today and On the Upcoming Years
  • Simplify Java Persistence Using Quarkus and Hibernate Reactive
  • Architecture and Code Design, Pt. 2: Polyglot Persistence Insights To Use Today and in the Upcoming Years
  • How to Store Text in PostgreSQL: Tips, Tricks, and Traps

Trending

  • Ethical AI in Agile
  • A Modern Stack for Building Scalable Systems
  • MCP Servers: The Technical Debt That Is Coming
  • Blue Skies Ahead: An AI Case Study on LLM Use for a Graph Theory Related Application
  1. DZone
  2. Data Engineering
  3. Databases
  4. Mapping Java Entities for Persistence in Hibernate (Part 1)

Mapping Java Entities for Persistence in Hibernate (Part 1)

Learn more about how to map Java entities for persistence in Hibernate.

By 
Mahmoud Anouti user avatar
Mahmoud Anouti
·
Aug. 06, 19 · Tutorial
Likes (6)
Comment
Save
Tweet
Share
37.0K Views

Join the DZone community and get the full member experience.

Join For Free

In this series of posts, we’ll explore how the domain classes in a Java application can be mapped to relational tables for persistence in a database using Hibernate. The goal is to summarize the techniques and best practices for correctly implementing the domain model of applications that need to load and store objects in an SQL data store.

To make examples easy to follow, our domain consists of simple entities representing books along with their authors, namely: a Book class, an Author class, and Publisher for representing the publisher of books. In this first part, the focus will be on basic mapping for the Book entity.

Declaring Entity Mappings

Before going through the examples, let’s review how mappings from object-oriented domain classes to relational tables are added to an application. There are two ways: (1) using annotations in Java code, and (2) using XML files using either JPA standard format or Hibernate hbm.xml files. In all the following examples, we will use annotations defined in the JPA standard and Hibernate specific annotations for features beyond what the JPA standard includes. Also, note that the target Hibernate version is 5.4 (which also supports JDK 11), but most of the details apply to either Hibernate 4.x and 5.x releases.

Basic Entity Mapping

The starting point for mapping a class is the JPA annotation @javax.persistence.Entity. It is required for enabling the persistence of the class. In addition, an identifier for the entity must be specified, mapping it to the primary key column using the @javax.persistence.Id JPA annotation. The most basic mapping is shown below.

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Book {

    @Id
    private Long id;

    ...
}


How does the identifier property (the id field) get its value? In this case, Hibernate expects you to set the value explicitly. In other words, if you try to persist a Book instance by creating it with the default constructor and calling session.save(), an exception will occur because the value of the identifier (and therefore the primary key column) is null (notice that id is of type Long, not the primitive long, which would have worked because it defaults to 0):

session.save(new Book());  // throws IdentifierGenerationException: ids for 
                           // this class must be manually assigned before
                           // calling save()


In this case, the id value must be assigned either via a constructor or a setter method. Normally, however, you want to let Hibernate automatically generate the identifier value, for example, using an auto-incremented column in the target table. This can be done using the @GeneratedValue annotation:

import javax.persistence.GeneratedValue;

@Entity
public class Book {

    @Id
    @GeneratedValue
    protected Long id;

    ...
}


The next question is: how exactly does Hibernate generate the id value? The answer is: It depends on the database vendor, or more specifically, the org.hibernate.dialect.Dialect subclass for the target database. Most of the time, it turns out to use either a sequence or an identity column as the strategy to generate the value. To be consistent from one database to another, it is best to specify the generation strategy explicitly. Hibernate provides several strategies. For example, enhanced-sequence is a generator strategy that uses a sequence to get the next value, and if the database does not support sequences, it falls back to a table simulating a sequence. Standardized generator strategies are defined in the enum javax.persistence.GenerationType. For example, to use the JPA standard sequence-based generator, we set the strategy to GenerationType.SEQUENCE:

@Entity
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    protected Long id;

    ...
}


To use the more powerful Hibernate generation strategies and to gain control over generation parameters, we can leverage the Hibernate @org.hibernate.annotations.GenericGenerator annotation:

@Entity
public class Book {

    @Id
    @GeneratedValue(generator = "idGenerator")
    @org.hibernate.annotations.GenericGenerator(name = "idGenerator",
             strategy = "enhanced-sequence",
             parameters = {
                 @org.hibernate.annotations.Parameter(name = "initial_value",
                                                      value = "100")
             })
    protected Long id;

    ...
}


This causes Hibernate to use the sequence (or a table simulating it) to get the next id value, starting at value 100, i.e. the first entity instance that gets persisted would have id value 100, the next would have 101, etc.

More on Basic Entity Mapping

Excluding Columns From Persistence

By default, all fields in the annotated class get included in the persisted rows, along with the primary column mapped by the id field (actually to be specific, all fields whose types are either basic built-in Java types or embeddable types, or serializable, or fields that are mapped using associations; other fields will cause an error). Let’s say Book has a title field, then it will be automatically mapped by Hibernate:

@Entity
public class Book {

    @Id
    ...
    protected Long id;

    protected String title; // No need for mapping annotation

    ... // getter(s) and setter(s)
}


Suppose we wanted to exclude title from being persisted, we can annotate by @javax.persistence.Transient or use the transient modifier:

import javax.persistence.Transient;

@Entity
public class Book {

    ...

    @Transient
    protected String title;

    ... // getter(s) and setter(s)
}


Controlling the Column Mapping

Now, let’s suppose that we do want the title field to be persisted, but we want to control its mapped column, for example, to make it NOT NULL, or maybe to change the name of the column. To do this, we use the @Column annotation:

import javax.persistence.Column;

@Entity
public class Book {

    @Id
    ...
    protected Long id;

    // Note that TITLE is already the default column name
    @Column(name = "TITLE", nullable = false)
    protected String title;

    ...
}


Now, Hibernate would throw an exception if a Book is persisted while having a null title. Hibernate also adds a NOT NULL constraint when generating the schema using its DDL generation tool (as configured by the setting hibernate.hbm2ddl.auto).

Table Naming

Another thing we might want to control is the name of the table mapped by the class. This can be done using @Table being placed on the class:

import javax.persistence.Table; 

@Entity
@Table(name = "BOOK")
public class Book {
   ...
}


Entity Naming

The @Entity annotation also has a name element, but this controls the entity’s name, not the table name. The entity name is used queries executed using Hibernate’s supported query syntax. For example, to select a book given its title, a query would be:

Query<Book> query = session.createQuery("from Book where title = :title",
                                        Book.class);
query.setParameter("title", "some title");
Book book = query.getSingleResult();


The entity name is by default the unqualified name of the class. If we have, for whatever reason, another Book entity class in another package, then we would need to change the entity name to avoid any naming conflict in the query.

Mapping an Immutable Class

Some of the entity classes may be designed to be immutable. In this case, the annotation @org.hibernate.annotations.Immutable can be used to tell Hibernate that it should ignore any updates to the entity. It helps improve performance by excluding the class from dirty checking during persistence operations.

@Entity
@org.hibernate.annotations.Immutable
public class Book {
   ...
}


Mapping Date/Time Fields

Fields of type java.util.Date and java.util.Calendar have a special mapping requirement in JPA. Such a field needs to be annotated with @javax.persistence.Temporal specifying whether the temporal type is a date, a time, or a timestamp. Note, however, that Hibernate works without @Temporal by defaulting to a temporal type of TIMESTAMP.

Let’s say we want to add a new field containing the publishing date for a book. We probably want the date to contain only the year, the month, and the day, without any time component. This can be done using by setting the @Temporal annotation as follows:

import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
public class Book {
    ...

    @Temporal(TemporalType.DATE)
    protected Date publishingDate;

    ...
}


This should map it to a SQL DATE type. Note that the default value of publishingDate is null. The user has to set it on the Book instance before saving it. If the field was instead creationTime representing the timestamp at which the object was inserted into the table, then we might want to have it auto-generated for us before insertion. To accomplish this, we can use the @org.hibernate.annotations.CreationTimestamp, as shown below.

@Temporal(TemporalType.TIMESTAMP)  // default in Hibernate
@CreationTimestamp
protected Date creationTime;


For an auto-generated timestamp upon an update, a similar @org.hibernate.annotations.UpdateTimestamp can be used.

Mapping Embedded Types

Some classes have semantics that makes them be part of or embedded in an entity instance, without them having an identity that makes them independent. For example, let’s say we want to have a class BookMetadata that contains some information about a book, e.g. a string containing the main topic. A Book would have a reference to a BookMetadata, but that instance does not have a separate identity or lifecycle. It is completely part of the Book object in the sense of composition in object-oriented terms. BookMetadata has essentially the same relationship as a String or a Date. We map it using an @Embeddable annotation to mark it as such:

import javax.persistence.Embeddable;

@Embeddable
public class BookMetadata {

    private String mainTopic;
    private boolean coauthored;

    ... // constructors, getters, setters
}

@Entity
public class Book {
    ...

    protected BookMetadata bookMetadata;

    ...
}


The important thing to realize on the mapped table side is that we now have one table called BOOK containing columns mapped by the Book class, plus the columns mapped by BookMetadata. Here is the generated schema:

create table BOOK (
    id bigint not null,
    coauthored boolean not null,
    mainTopic varchar(255),
    publishingDate timestamp,
    title varchar(255) not null,
    primary key (id)
)


We may want to change the name of a column in the embeddable field. To do this, we need to override the mapping of the fields of BookMetadata using the annotation @AttributeOverrideapplied on the owning entity, as shown below:

import javax.persistence.AttributeOverride;

@Entity
public class Book {

    ...

    @AttributeOverride(name = "mainTopic",
               column = @Column(name = "TOPIC", length = 60, nullable = false))
    @AttributeOverride(name = "coauthored",
               column = @Column(name = "CO_AUTHORED"))
    protected BookMetadata bookMetadata;

    ...
}


Note that we also changed the length of VARCHAR from 255 to 60 within the overridden @Column mapping for mainTopic, and made it not nullable. The resulting schema is then:

create table BOOK (
    id bigint not null,
    CO_AUTHORED boolean,
    TOPIC varchar(60) not null,
    publishingDate timestamp,
    title varchar(255) not null,
    primary key (id)
)


In the upcoming posts, we will explore more topics on entity mapping, including mapping collections, classes with inheritance, and more. Stay tuned...!

Relational database Database Hibernate Java (programming language) Persistence (computer science) sql

Published at DZone with permission of Mahmoud Anouti, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Architecture and Code Design, Pt. 1: Relational Persistence Insights to Use Today and On the Upcoming Years
  • Simplify Java Persistence Using Quarkus and Hibernate Reactive
  • Architecture and Code Design, Pt. 2: Polyglot Persistence Insights To Use Today and in the Upcoming Years
  • How to Store Text in PostgreSQL: Tips, Tricks, and Traps

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!