Hibernate by Example – Part 2 (DetachedCriteria)

So last time we helped out justice league to effectively manager their super heroes. Today we focus on how The Avengers will be using Hibernate’s Detached Criteria to find out their enemies with respect to each superhero so as to protect their super heroes.

You can download the working example from here.

In this example we take only two entities into consideration. The Avenger & The Villain. We build a relationship between the two using a join table. Let us have a look at the domain mappings used in this example.

package com.avengers.domain;
 
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
 
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
 
import org.hibernate.annotations.Type;
 
/**
 * The domain class representing each member of the avengers
 * 
 * @author Dinuka.Arseculeratne
 * 
 */
@Entity
@Table(name = "Avengers")
public class Avenger implements Serializable {
 
 /**
  * The primary key of the Avenger table
  */
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 @Column(name = "avenger_id")
 private Long avengerId;
 
 /**
  * The name of the avenger member
  */
 @Column(name = "avenger_name")
 private String avengerName;
 
 /**
  * A flag which holds whether the avenger's powers are awesome
  */
 @Type(type = "yes_no")
 @Column(name = "is_awesome")
 private boolean isAwesome;
 
 /**
  * The list of enemies the avenger has
  */
 @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
 @JoinTable(name = "AVENGERS_AND_VILLAINS", joinColumns = { @JoinColumn(name = "avenger_id") }, inverseJoinColumns = { @JoinColumn(name = "villain_id") })
 private List<Villain> enemyList = new ArrayList<Villain>();
 
 public Long getAvengerId() {
  return avengerId;
 }
 
 public void setAvengerId(Long avengerId) {
  this.avengerId = avengerId;
 }
 
 public String getAvengerName() {
  return avengerName;
 }
 
 public void setAvengerName(String avengerName) {
  this.avengerName = avengerName;
 }
 
 public boolean isAwesome() {
  return isAwesome;
 }
 
 public void setAwesome(boolean isAwesome) {
  this.isAwesome = isAwesome;
 }
 
 public List<Villain> getEnemyList() {
  return enemyList;
 }
 
 public void addEnemy(Villain enemy) {
  enemyList.add(enemy);
 }
 
 @Override
 public String toString() {
  return "Avenger [avengerId=" + avengerId + ", avengerName="
    + avengerName + ", isAwesome=" + isAwesome + ", enemyList="
    + enemyList + "]";
 }
 
 
}
 

This class maps an avenger. I have used minimal fields in order to keep this example as simple and short as possible. And the Villain domain looks as follows;

package com.avengers.domain;
 
import java.io.Serializable;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
 
import org.hibernate.annotations.Type;
 
/**
 * This class represents the Villain forces against the avengers
 * 
 * @author Dinuka.Arseculeratne
 * 
 */
@Entity
@Table(name = "Villains")
public class Villain implements Serializable {
 
 /**
  * The primary key of the Enemy table
  */
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 @Column(name = "villain_id")
 private Long villaiId;
 
 /**
  * The name of the enemy
  */
 @Column(name = "villain_name")
 private String villainName;
 
 /**
  * A flag which checks whether the villain is super awesome
  */
 @Type(type = "yes_no")
 @Column(name = "is_awesome")
 private boolean isAwesome;
 
 public Long getVillaidId() {
  return villaiId;
 }
 
 public void setVillaidId(Long villaidId) {
  this.villaiId = villaidId;
 }
 
 public String getVillainName() {
  return villainName;
 }
 
 public void setVillainName(String villainName) {
  this.villainName = villainName;
 }
 
 public boolean isAwesome() {
  return isAwesome;
 }
 
 public void setAwesome(boolean isAwesome) {
  this.isAwesome = isAwesome;
 }
 
 @Override
 public String toString() {
  return "Villain [villaiId=" + villaiId + ", villainName=" + villainName
    + ", isAwesome=" + isAwesome + "]";
 }
 
}

Ok now that we have defined our domains, let us see how data retrieval happens with DetachedCriteria. I have used DetachedCriteria here because The Avengers were very specific and said they do not want anything to do with the Hibernate session, so hence i used DetachedCriteria which does not require a hibernate session to be present.

Our primary objective is to retrieve The Avenger to whom a villain belongs to. Note that this assumes the same villain cannot be a villain to more than one superhero. So moving on i give below the method that retrieves an avenger based on the villain name passed.

public Avenger retrieveAvengerByVillainName(String villainName) {
 
  Avenger avenger = null;
  /**
   * Selected a detached criteria so we do not need a session to run it
   * within.
   */
  DetachedCriteria criteria = DetachedCriteria.forClass(Avenger.class);
 
  /**
   * Here we are doing an inner join with the Villain table in order to do
   * a name comparison with the villainName passed in as a method
   * parameter
   */
  DetachedCriteria villainCriteria = criteria.createCriteria("enemyList");
 
  villainCriteria.add(Restrictions.eq("villainName", villainName));
 
  villainCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
 
  @SuppressWarnings("unchecked")
  List<Avenger> avengerList = getHibernateTemplate().findByCriteria(
    criteria);
 
  if (!avengerList.isEmpty()) {
   avenger = avengerList.get(0);
   getHibernateTemplate().initialize(avenger.getEnemyList());
  }
  return avenger;
 
 }

In this method what we do is first we create a criteria for our master class which in this case is Avenger.class. Then we need to do a join with the Villain table and hence we create a sub criteria from our main criteria with the name of the list we defined within the Avenger domain class.

Then it is a matter of equaling the property of the Villain domain to the villain name passed in.

The power of the Criteria API is such that you can create dynamic queries with ease which would be a hassle if we were to use pure HQL which would require substantial string concatenations in order to achieve the same.

A sample test class called AvengerTest.java is given with the attachment which you can find at the top of the most. Note that you need to remove the comment on avenger-context.xml in order to create the tables needed for this example.

So that is about it.

The Avengers can be risk averse now that they have a system by which they can relate any super villain to a super hero within their league.

As always your comments and suggestions are always welcome and appreciated.

Thank you for taking the time to read!!!!

Reference: Hibernate by Example – Part 2 (DetachedCriteria) from our JCG partner Dinuka Arseculeratne  at the My Journey Through IT blog

Related Articles :
Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

Leave a Reply


− 1 = five



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books