BitterSweetJaVa

November 30, 2009

Retrieve DB Objects from a legacy system using Hibernate

Filed under: Java, ORM — Tags: , , , , , — .|2ic|K @ 4:22 PM

Problem: Load data from multiple tables into a single Java entity.

Approach 1: Use custom SQL loading


@Entity
// Class that will store the query result(s). Class field names are the same than database column names.
@SqlResultSetMapping(name = "customerMapping", entities = @EntityResult(entityClass = CustomerMapping.class))
// Using hibernate annotation to specify out custom SQL queries
@org.hibernate.annotations.NamedNativeQueries(
     {
      @NamedNativeQuery(name = "loadAllCustomers",
      query = "select a.col1,a.col2,b.col1 from table1 a, table2 b where a.col5=b.col5",
      resultSetMapping = "customerMapping"),
      @NamedNativeQuery(name = "loadByCustNum",
      query = "select a.col1,a.col2,b.col1 from table1 a, table2 b where a.col5=b.col5 and a.col1 = ?",
      resultSetMapping = "customerMapping")
     }
)
// Default SQL query to be used when loading this entity through Hibernate
@Loader(namedQuery = "loadByCustNum")
public class CustomerMapping implements Serializable {
... class body
}

Approach 2: Use one-to-one mapping approach


@Entity
@Table(catalog = "myDB", schema = "dbo", name = "customer_mapping")
public class CustomerMapping implements Serializable {
     @OneToOne
     // Foreign Key pointing to the corresponding CustomerMaster data.
     @JoinColumn(name = "gte_cust_num", unique = true, nullable = true)
     // Default hibernate action to be taken when the FK is not null and
     // it's not present in the secondary table.
     // Hibernate can ignore the error and do nothing or throw an exception.
     @NotFound(action=NotFoundAction.IGNORE)
     private CustomerMaster masterData;
... class body
}


@Entity
@Table(catalog="myDB", schema="dbo", name="customer_master")
public class CustomerMaster implements Serializable {
... class body
}

NOTE: Be careful when trying to retrieve the objects using HQL:

hql = "from CustomerMapping cmi where cmi.filterField = 'ABCXXX'";

The query above will result in a performance issue if we are retrieving several CustomerMapping objects. This is because hibernate will generate one query to get all the CustomerMapping objects and N queries to get the data to populate each CustomerMaster object (from the one-to-one relation).

SELECT A,B,C FROM CustomerMapping WHERE filterField = 'ABCXXX';
SELECT D,E,F FROM CustomerMaster WHERE id = ?;
SELECT D,E,F FROM CustomerMaster WHERE id = ?;
SELECT D,E,F FROM CustomerMaster WHERE id = ?;

In other words, if we are retrieving N objects, then we will have N+1 database queries.

In order to avoid this, we need to force Hibernate to use JOIN FETCH to retrieve the CustomerMaster data:

hql = "from CustomerMapping cmi left join fetch cmi.masterData where cmi.filterField = 'ABCXXX'";

The query above will produce only one sql query to retrieve CustomerMapping and CustomerMaster data using a join.

SELECT A,B,C FROM CustomerMapping LEFT JOIN CustomerMaster (....) WHERE filterField = 'ABCXXX';

Advertisement

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Theme: Shocking Blue Green. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.