Tuesday, May 1, 2012

Custom Entity Creation in Hibernate



CUSTOM ENTITY CREATION

We can create entity class of a table using hibernate and pojo. And it can be used with hibernate query and hibernate native sql queries.`@Entity` annotation is used to identify the entity class.
Assume that we use hibernate query to return particular result from table and map the result to entity.
Example :-
we have 2 table named `shop_type` and `shop`
And we set `shop_type_id` as foreign key for `shop ` table

table `shop_type`
shop_type_id
name
1
Hotel
2
M.Market
3
Textile

table `shop`
shop_id
shop_type_Id
name
entry_date
1
1
AVN
03/16/12 12:05 AM
2
1
AKN
03/16/12 12:10 AM
3
2
Reliance m
03/16/12 12:15 AM
4
3
AnimalTXT
03/16/12 12:20 AM


Assume that we have 2 entity classes named `Shop` and `ShopType`
and so we have two entity classes.  if we want to select a particular details from 'shop' table we can simply use our hibernate query
         eg:- hql  = "from Shop s where s.shopId = ?";
                     Query query = session.createQuery(hql);
                     query.setInteger(0, shopId);
                     (Shop)(query.uniqueResult());


and when we execute this statement . Hibernate will include all column of `shop` table in select statement by default and its a background process doing by hibernate. The reason for this behavior is only then  hibernate can map this result to corresponding entity class here it is `Shop.class`.

Example for background process is something like this
  select s.shop_id,s.shop_type_id,s.name,s.phone_number from shop s whee
  s.shop_id = 1;

 we can also use our native sql query also for select the result.

 Eg :- sql = "select {s.*} from shop s where s.shop_id = ?";
         SQLQuery query = session.createSQLQuery(sql);
         query.addEntity("s", Shop.class);
         query.setInteger(0, shopId);
        (Shop)(query.uniqueResult());

In this case also we need to select full column in our select statement.'{}'  symbol
is used when selecting all columns  and this tells the hibernate that all fields are selected.

Until now we select all column from table using select statements and mapped it to corresponding entity. And we find that without this way we can't map the result to entity.
Good news is that there is a way to select specified columns from a table using hibernate native sql quires.
using .addScalar property we can achieve this.

Eg:-
 sql = "select s.name as sname from shop s where s.shop_id = ?";


SQLQuery countQuery = session.createSQLQuery(hql).addScalar("sname",Hibernate.STRING)
return ((Object[]) countQuery.uniqueResult());
But using this properties we can't map the result in to entity class and it only return  objects .

Until now the result set column names are assumed to be the same as the column names specified in the mapping document. This can be problematic for SQL queries which join multiple tables, since the same column names may appear in more than one table. Assume that if we have a situation and we want to join two table and select only 3 columns . So we can use  addScalar property but if we need to select 10 columns then  addScalar will not be a proper way to accomplish this task. Because using lots of addScalar properties will  complicate our task and traveling of data will be more difficult. Also if we pass this result to velocity there will be difficulties.

So in this case we can use  custom entity like classes for mapping our join query result. Using this way we can reduce complexity and it behave like an entity class object. We can use it anywhere we like. To doing this we need to create a java class.
This example will give you an clear idea.

We have a sql query
 sql = SELECT s.`name`,st.name,,s.entry_date  FROM shop s JOIN shop_type st ON(s.type_id = st.shop_type_id);

This will return
name
name
entry_date
AVN
Hotel
03/16/12 12:05 AM
AKN
Hotel
03/16/12 12:10 AM
Reliance m
M.Market
03/16/12 12:15 AM
Animal TXT
Textile
03/16/12 12:20 AM

 And i am trying to map the result in to an custom entity to doing this we need  to create a class just like entity class . And this class must have variables. And

1.Variable name must be same as column names in our select statement
2.must include getter and setter methods for that variables .
3.Data type of variable also same as in table .

Here data type of column entry_date is Date in database and so variable `entryDate`.We can see that here some column have same  names.[1st and 2nd column have same name]and this will make some problems in our entity because there is an ambiguity. To solve this we can use alias in our query and so the column name will change

eg :- SELECT s.`name` as shopName,st.name as typeName,s.entry_date as entryDate  FROM shop s JOIN shop_type st ON(s.type_id = st.shop_type_id);

This will return
shopName
typeName
entryDate
AVN
hotel
03/16/12 12:05 AM
AKN
hotel
03/16/12 12:10 AM
Reliance m
M.market
03/16/12 12:15 AM
Animal TXT
textile
03/16/12 12:20 AM

So we can see that now 3 column have different names 'shopName' and 'typeName',entryDate respectively. Use this names for creating variable for class `ShopView` .Now we can create our custom entity class .

Created Class
public class ShopView {
   
    private String shopName;
    private String typeName;
    private Date  entryDate

    public String getShopName () {
        return shopName;
    }

    public void setShopName(String shopName) {
        this. shopName = shopName;
    }

    public String get TypeName () {
        return typeName;
    }

    public void setTypeName (String typeName) {
        this. typeName = typeName;
    }
    public Date getEntryDate() {
        return entryDate;
    }

    public void setEntryDate(Date entryDate) {
        this.entryDate = entryDate;
    }
}

ShopView is our new custom entity class for mapping our result.
For mapping our result to our newly created class we need to  use              query.setResultTransformer(Transformers.aliasToBean(ClassName.class)); method

For our Example we can use like this.

Sql ="SELECT s.`name` as shopName,st.name as typeName,s.entry_date as entryDate  FROM shop s JOIN shop_type st ON(s.type_id = st.shop_type_id)";
SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(Transformers.aliasToBean(ShopView .class));
pager.setResult(query.list());

A ResultTransformer is a nice and simple interface that allows you to transform any Criteria result element.
  The above query will return a list which has been instantiated and injected
  into its corresponding properties or fields in ShopView class.   Using this way we can
  map our result into any class. This way is  suitable in   case of sql views. Means we
  can create custom view entities for our needs.

  Use this object in velocity page example.
   Assume that  we passed  the result  to velocity and we set the name as `shopDetailsList`
  then  we can use the list  in velocity as
   #foreach($shopObj in $shopDetailsList)
      $ shopObj .shopName
      $ shopObj .typeName
   #end



No comments:

Post a Comment