Custom Search

Tuesday, August 12, 2008

Flush Modes in Hibernate

This is a short tutorial or i could say short explanation of different flush modes available in Hibernate.

Question:What is flush mode in hibernate
Answer: As we already aware that hibernate maintains objects in cache before actually comitting a session.When we commit a session hibernate synchronizes cached data with the database. We can control this behaviour by setting the flushmode property by calling "session.setFlushMode()"

Hibernate provides us with three different flush modes

1.AUTO(FlushMode.AUTO) : By setting this mode we are actually leaving the option to hibernate like when to flush the data from session to database. Hibernate knows how to deal this. For example if we have updated some table and then when we query to the same table we should get the updated data. In this situations hibernate flushes the data before we actually execute the query since we need the updated data.

2.COMMIT(FlushMode.COMMIT) : This mode tells hibernate that flush the data from the cache at the end of every transaction.

3. NEVER(FlushMode.NEVER) : This mode allows flushing the data when we actually call the method Flush().

Based on our application requirements we have to set the flush mode.Nomrally people prefer not to touch the flush mode setting.Some times if we use COMMIT as the flush mode then we may end up with bad data which causes dirty reads.



Wednesday, July 30, 2008

Fetching association with Hibernate Criteria Query

What is Criteria Query?

Why do we need this?

When is this used?



Here are the answers.... with examples

We have an online shopping application where the user can place an order. This application provides a JSP with search criteria like ShopName,PublisherName,BookPriceRange and availability(One can add their own search criterias) .Inorder to fetch the results our query should be formed in such a way that the parameters should be added run time(as the user selects can select only shopname sometimes both shopname and publisher).Now the criteria queries comes in hand. Based on the user selection we will do necessary validation and build up the SQL query dynamically. I think you got the answers.Now we will drive directly into an example.

Lets think about what the search results should contain.. Bookname,PublisherName,ShopAddress,Cost of the Book. In this application we have three pojo's and 3 corresponding tables and they are
1.Shop(Association type with book is one to many )
2.Book(Association type with publisher is one to many )
3.Publisher
So as per above, the shop class contains set of books and book class contains publisher id. Now lets see how will we build the query

1.Criteria criteria = session.createCriteria(Shop.class,"shop")
2. .createCriteria("Books","book")
3. .add(Restrictions.eq("shop.Name",shopname))
4. .add(Restrictions.between("book.price",minPrice,maxPrice))

lets understand the above 4 lines.Before explaining them, assume shopname,minPrice,MaxPrice are the parameters passed from the presentation layer i.e the user entered values in the search criteria.
First line is as usual it says hibernate to fetch all the data from Shop table.
Second line makes a join with the book table.

Question:Why do we need to join shop and book
Answer : valid doubt, since the Shop is already having an association mapping called books to Book class. whenever hibernate queries for Shop it fetches the data from book table also. But it depends on whether your association has lazy=false or not.Normally we prefer lazy=true for associations so in that case we have to do one more select by giving Shop.getBooks().
Alternatively, here in our online shopping application the user enters the book name, so based on this criteria we want to limit the number of books being fetched.This is the reason we are joining with Book class.

Third and Fourth lines are restrictions i.e. our query criteria;s in where condition of SQL queries.

Now lets go further and see what happens if the user has entered publisher name in the search criteria.In that case we need to join Publisher table.

Note that I am adding lines to the same above query

1.Criteria criteria = session.createCriteria(Shop.class,"shop")
2. .createCriteria("Books","book")
3. .add(Restrictions.eq("shop.Name",shopname))
4. .add(Restrictions.between("book.price",minPrice,maxPrice));
5. if(publishername!= null)
6. criteria.createCriteria("Publisher","publisher")
7. .add(Restrictions.eq("publisher.Name",publishername)) ;

Fifth line checks whether the user entered any publishername if there is any then we need to Join publisher table thats what we are doing in second line and seventh line is a restriction on publisher name.

Note: restrictions are nothing but the condition we put after "where" in sql query.

What happens if i say criteria.list() ?
It fetches all the data from the three tables shop,Book,Publisher..

answer is no

why . if you can go back and see the query once again our first criteria query is on the entity and the other 2 criterias are on the association mappings.So the result contains data from Shop table
But our main aim is to fetch data from all the three tables here comes the usage of projections.

Question: what are Projections in hibernate and how are they used.
Answer: i will explain with an example in our shop table suppose if i only want shopname then my query would be formed like this

select shopname from shop instead of select * from shop

this is what a projection do it basically fetches the selected columns from the table.

Coming to our dicussion how can we use projections here. take the same old query and set the projection as bellow.


criteria.setProjection(Projections.projectionList().add(Projections.property("shop.name"),"shopname").add(Projections.property("book.name"),"BookName"))


Here i have created a list of projections for the selected columns(column names should prefix with table alias specified in criteria query if you are confused look into our first criteria query once).


This gives the list of Object[] array.


In order to transform this array to a map with key as alias please refer my earlier post.
http://prasadmarrapu.blogspot.com/2008/07/result-transformers-in-hibernate.html

Want to see tutorials on more Technologies and latest updates go to
http://prasad.marrapu.googlepages.com

Tuesday, July 29, 2008

Result Transformers in Hibernate

What Result Transformers do... in hibernate.... Let me give you some introduction about this then we will see an example using one of the result transformer..

Result transformers as the name suggest they are used to transform the results returned by our hibernate query to a specific format or I would say to a bean or a map.

Normally , when you query for data in hibernate it returns a domain object in that case we may not find much use of Result Transformers.Suppose if we write a query to return only selected columns, then hibernate returns a list of object array. This object array represents the columns for each row.Still not getting my point lets see with an example

Before giving the example, I am not going to tell you how to get the hibernate session and all stuff as it is of not much importance to us now.

I have a pojo "Employee" with properties like id,name..etc and it is mapped to a table. Now I have a requirement to fetch the employee name and Salary for all employees. For this i am going to write a Named query in my Employee.hbm.xml


<sql-query name="getEmployeeData">
<return-scalar type="java.lang.String" column="empname ">
<return-scalar type="java.math.BigDecimal" column="salary">
SELECT empname as name , salary as salary FROM Employee
</sql-query>


So when i call the above namedQuery it actually fetches the data in a list of object array as already dicussed.In order to acutally show the data I have to do following things..

List results= session.getNamedQuery("getEmployeeData").list();

To get the first Employee data

Object[] data =results.get(0);
String ename = (Long)data[0];
BigDecimal sal = (BigDecimal)data[1];

As the example shows we have to based on indexing data.Think how it would be if we can get the data based on our actual aliases we provided in the named query.This is what a hibernate resultTransformer will do.We have to set them as per our requirements.

Question: How to set the transformers.
Answer: see below example ...

Hibernate has a 'Transformers' class which has the following resulttransformers(To know in deep please refer the actual implementation of this transformers)

1.Transformers.ALIAS_TO_ENTITY_MAP
2.Transformers.TO_LIST
3.Transformers.aliasToBean

First one as the name tells it converts the result i.e. List of Object Array with list of maps with alias as key...
going back to our example what happens if i set this transformer to our query lets see...

List results= session.getNamedQuery("getEmployeeData").setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();

Now to get the first employee i have to do something like this

Map data =(Map)results.get(0);
String ename = (Long)data.get("empname");
BigDecimal sal = (BigDecimal)data.get("salary");

These aliases are given by us in the named query(Please refer the named query given earlier in this example).

So its easy to depend on this keys rather than on indexing data. But if one feels that sending a map from service to client costs(I dont have much idea on performance cost) more then we have to depend on index based data.

Want to see tutorials on more Technologies and latest updates go to http://prasad.marrapu.googlepages.com