On Java Development

All things related to Java development, from the perspective of a caveman.

Describing a Header/Detail Relationship using JPA Annotations With Hibernate

without comments

Introduction

This post shows how to describe a header/detail relationship (HDR) to Hibernate using files that have a composite key and those with identity records.

The first example presented uses files that have identity fields as their primary key. These fields are described on the physical file. Other fields can be isolates as key fields which would then be described using logical files. On other machines these files are called indexes.

 

Mapping Using Identity Fields

In this example, the relationship is between the Premium Request Header and the Premium Request Detail. These files were created with identity fields that act as the primary key field. Logical files or Index files are created for other fields as needed.

 
The Header Record
This file represents the header side of the HDR. The identity field for this file is PRHRECID. It is defined so that the system always generates a unique number for every record added and to always be incremented by 1. The SQL Data Definition Language (DDL) source is shown below. Note lines 26-28 used to define this key field.

For every Java application that uses Hibernate, a class known as an Entity must be created. Think of an entity as a collection of fields which have so-called “setter” and “getter” methods that are called to set and retrieve the data values for each field (“property” is the Java term). For the RPG-er, an entity can be thought of as a record format described using a data structure however, direct access to the fields is prohibited. Instead, the setter and getter methods are used for this. Classes of this type are also known as a “Plain Old Java Object” or simply, a POJO. When a class of this kind is used by Hibernate to write a record to the file it is called an “Entity”. The definition of an entity is;

A persistence entity is a lightweight Java class whose state is typically persisted to a table in a relational database. Instances of such an entity correspond to individual rows in the table. Entities typically have relationships with other entities, and these relationships are expressed through object/relational metadata. Object/relational metadata can be specified directly in the entity class file by using annotations, or in a separate XML descriptor file distributed with the application. ref: Wiki

Shown below is the Java entity class for file PHSPRRQHD. All properties (fields) have been annotated with @Column to tell Hibernate these are properties which must be persisted to the file.

Lines 65-66also begin with the @Column annotation but also have @Id @GeneratedValue(strategy = GenerationType.AUTO ) to tell Hibernate this is the identity field and to automatically generate its value whenever the record is written. After that, it never changes.

Line 68 uses the annotation @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) to tell Hibernate that the list of premium request recalculation detail records have a one-to-many relationship with this header record. In addition, Hibernate is being told to eagerly load the detail records into this property, which is a list or a collection object. Loading the records in this manner is immediate. The alternative is to lazily load which means the records aren’t actually loaded until this property is read by way of calling its so-called “getter” method that returns the list to the caller.

The next entry supplied for this property is @JoinColumn(name=”PRDREQID”, referencedColumnName = “PRHREQID”). This informs Hibernate that the field indicateds will be used to join the header and detail records.

It may not be apparent by looking at these annotations, but the ramifications of this join allows Hibernate to read the header record and the detail records will accompany the header automatically. The mechanics of this will be shown in an up-coming section.

This describes the header record to Hibernate and defines its relationship to the detail records.

 
 
The Detail Record
This file represents the detail side of the HDR. The identity field for this file is PRDRECID. It too is defined so that the system always generates a unique number for every record added and to always be incremented by 1. The SQL Data Definition Language (DDL) source is shown below. Note lines 26-28 used to define this key field.

Shown below is the Java entity class for file PHSPRRQDT. As with the header file, all properties have been annotated with @Column to tell Hibernate these are properties which must be persisted to the file. Lines 61-62 also begin with the @Column annotation but also have @Id @GeneratedValue(strategy = GenerationType.AUTO ) to tell Hibernate this is the identity field and to automatically generate its value whenever the record is written. After that, it never changes.

No other annotations are required.

 
 
Using Hibernate to read the Request Header record
This section shows how Hibernate is used to read the header record acquiring the detail records in the same process.

Shown below is the Java code of the managed bean used to retrieve the Request Detail records for display. It simply instantiates a Request Header entity and populates the properties with the values for Company, Block and Policy. Next, it instantiates a service object and calls the method getRequestDetailRecords, passing the Request Header entity object as a parameter.

Shown below is the service class method called getRequestDetailRecords used for this purpose. The method accepts the Request Header entity as an argument.

The first task is to instantiate the DAO responsible for performing the data retrieval and initializing a new arraylist to hold the resulting detail records. This work is shown on lines 7 and 8, below.

The next task is to start a transaction, call the DAO passing the Request Header and then completing the work by committing the transaction. The list of Request Detail records is then returned back to the managed bean for display. It’s pretty straight forward. Now, we’ll look at the DAO where calls to Hibernate are made.

 
The DAO
This is the method that was called by the service presented above.

It accepts the Request Header entity object that contains the Company, Block and Policy. The logic pulls out the request ID that has been assigned to the header and detail records. (This is not the primary key field, which is the identity field.) Next, the logic creates a list to hold the header record and another to contain the detail records.

Line 12 shows the call made to the method of this same DAO that is responsible for reading the Request Header record. Because of the @OneToMany annotation to the header entity, this I/O will automatically retrieve the associated detail records.

When the call returns, the header record will be in the list called listOfPHSPRRQHDRecords. Of course, there will only be 1 header record returned.

Lines 15 and 16 of getRequestDetailRecords pulls the header record from the list and in the process, casting it to the entity class. Next, it calls the method to retrieve the detail records, parking it into listOfPHSPRRQDTRecords and returns to the service class and ultimately back to the managed bean.

 

Mapping Using Composite Key Fields

In this example, the relationship is between the Policy Master and the Rider file. Since these files were created before the advent of identity fields now available on the iSeries, Hibernate must use what are called Composite Keys. For more information on describing composite keys see this.

 
The Header Record
Shown below is a segment of the entity for the Policy Master file.

Line 16 shows the annotations used to tell Hibernate that this property contains the embedded ID properties that have been placed into the class PSPMPOLPK01 . Having done this, the properties in this class (PSPMPOL) describing these fields have been commented out.

Lines 41 and 45 describe the setters and getters for PSPMPOLPK01.

Lines 47-52 use JPA annotations to indicate that there is a one-to-many relationship between this file (the policy master) and the rider file, the records of which are to be held by this property (listOfRiders). It also indicates which fields are to be used to join the policy master to the associated rider records. The annotation entry of cascade=CascadeType.ALL means that the persistence will propagate (cascade) all EntityManager operations (PERSIST, REMOVE, REFRESH, MERGE, DETACH) to the relating entities. So, if the policy is deleted, the operation will cascade across all riders so that an orphan condition is prevented.

The Composite Key Class
This is the Java code for PSPMPOLPK01. It contains the key fields, which have been commented out in the class above. This describes the composite key structure and is embedded inside of PSPMPOL.

 
The DAO
Below is the Data Access Object used to read the policy master. The method accepts the key-field values to be used for the retrieval operation. The process begins by instantiating the class PSPMPOLPK01 that contains the key fields that were commented out of the entity class, PSPMPOL. Next, it uses the setter methods to set the values.

Lines 11-17 uses the entityManger object to find the specified record checking for a not-found condition so that the appropriate message can be propagated up the call stack and back to the user interface.

This completes this topic.

 
Summary
This post showed how to define a header and detail relationship using JPA annotations. It showed how these annotations simplifies the I/O process resulting in very little Java code.

Written by admin

January 30th, 2014 at 2:22 pm

Leave a Reply

You must be logged in to post a comment.