SQL Zone is brought to you in partnership with:

I currently work in the capacity of Software Engineer at a reputed company in Sri Lanka. I'm most keen in J2EE Technologies and love working with open source libraries which fit my project needs. Very interested in the NoSQL concept and experimenting with various products to find a good blend for our projects within the company. Part time freelancer. Avid contributor in the stackoverflow arena. Android is another area which I am looking at with very keen interest as I believe mobile development is the way forward. Dinuka is a DZone MVB and is not an employee of DZone and has posted 24 posts at DZone. You can read more from them at their website. View Full User Profile

Hibernate by Example - Part 2 (DetachedCriteria)

11.11.2011
| 26164 views |
  • submit to reddit

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!!!! 

From http://dinukaroshan.blogspot.com/2011/11/hibernate-by-example-part-2.html

Published at DZone with permission of Dinuka Arseculeratne, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Amara Amjad replied on Sun, 2012/03/25 - 2:07am

Keep It Up .good work .. Explore JOIN Fetch too .. thas handy when you join stuff..

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.