Wednesday, July 16, 2008

Doing StoredProcedures as NamedQueries in Hibernate and JPA Java Persistence API or EJB3.0

Here are some wise words of wisdom regarding stored procedures and Hibernate from Mark Spritzler from the JavaRanch:

In Hibernate there are some caveats to stored procedures.

1. Only one out parameter and it must be the first parameter
2. The out parameter must be a refcursor. No other types will work.

If you have to work with a stored procedure that returns a varchar, you can call session.getConnection() and work directly with the jdbc connection. Although in this case you can't use a named query.

How to Map an Integer Column Value of 0 (zero) to a null, in Hibernate with MySQL Oracle or DB2?

A question I often get is how to map a zero 0 value to a null value in the database.

According to Gavin King, the man behind Hibernate, the way to map 0 to null is to write a UserType that transforms 0 to null, and use that custom UserType as the identified type. Hibernate will not create a schema with default values, so in this case, you're on your own.

Another neat Hibernate trick is to use the nullif function in HQL. It's slick:

from Clazz c where nullif(c.cat, 0) is null

If both expressions are equal, null is returned, otherwise the first expression is returned, as you would expect. This simply helps out in the coding for the null or zero values.

Hibernate Forum Topic on Mapping a 0 to a null...




Solve ORA-01002: Fetch Out Of Sequence Error Message Oracle Dialect

This is an error that is generated specifically by Oracle. It can happen under a variety of circumstances, but lets look at what the Oracle database documentation says:

ORA-01002: fetch out of sequence

Cause: This error means that a fetch has been attempted from a cursor which is no longer valid. Note that a PL/SQL cursor loop implicitly does fetches, and thus may also cause this error. There are a number of possible causes for this error, including: 1) Fetching from a cursor after the last row has been retrieved and the ORA-1403 error returned. 2) If the cursor has been opened with the FOR UPDATE clause, fetching after a COMMIT has been issued will return the error. 3) Rebinding any placeholders in the SQL statement, then issuing a fetch before reexecuting the statement.

Action: 1) Do not issue a fetch statement after the last row has been retrieved - there are no more rows to fetch. 2) Do not issue a COMMIT inside a fetch loop for a cursor that has been opened FOR UPDATE. 3) Reexecute the statement after rebinding, then attempt to fetch again.


This can all be confusing. And it can be frustrating.

Sometimes, I've seen this simply due to data in the database problems. If it's troubling you, do a small query on your Oracle8i or 9 database and see if you are searching past the last record in the returned list. If you are, you might just be missing data or something in your database - phantom rows!

"After enabling Hibernate log and DB trace, we noticed 2 records missing in the DB, and it seems that this caused the problem. So, for now, I would say that the problem isn't related to hibernate." -Hibernate.org Forum Posting

I've also seen this caused by people looping through a ref cursor that is being used as an out parameter in the code. Instead, you can avoid the ORA-01002: Fetch Out Of Sequence Exception by opening two different and separate database cursors, and use one as the out parameter, and use the other cursor throughout the loop. -orafaq.com

Monday, July 14, 2008

Can Hibernate Map to a Database View Without A Primary Key Defined?

If you're not updating or creating new rows in the view, you can simply map an entity to the db2 view or oracle view. That's usually the easiest thing to do when mapping db views.

And while views don't have primary keys it is very easy to define a view that has a surrogate key. I'd recommend this to easy the pain of mapping it.

Hibernate and a Database View

Here's some info from Hibernate.org:

"Does Hibernate3 support database views?

Of course. From the point of view of Hibernate, a view is just like any other table (except that you might not be able to update or insert to a view). You can easily map a class to a view by specifying table="view_name".

In Hibernate3, you may even map an entity class to a SQL query result set using the subselect mapping element. This is useful if you are unable to define new views in your database. "

Using Hibernate and Database Views

My Hibernate Tutorials

My WebSphere Tutorials
My Sun Certification Mock Java Exams
My Portlet Development and Portal Administration Tutorials

Friday, July 11, 2008

Review: Hibernate Made Easy: Simplified Data Persistence with Hibernate3 and JPA Annotations (Java Persistence API)

Here's a great review I just received on amazon.

You know, I really love getting feedback for my books. I appreciate criticism, I incorporate updates and fixes quickly, and I always take feedback seriously. The nice thing about self-publishing is that I can get updates, changes and improvements into press within a few weeks.

Anyways, I just got this review from who I consider to be a new friend, on Amazon.com. Certainly made my day, which is quite an accomplishment on a day when the DOW dropped below 11000. :)

***
Hibernate3 & JPA Book Review: Hibernate Made Easy


5.0 out of 5 stars An excellent step by step guide to learning Hibernate, July 11, 2008
By J. Dewberry (Atlanta, GA United States) - See all my reviews
(REAL NAME)
I love this book. I wish all technical books were written this way.

A few months ago, I had a job interview and they asked me if I knew Hibernate. I told them that I didn't know it, but i could learn it. So they gave me a little sample database problem - they wanted me to build a one-to-many, bi-directional join - and asked me to spend the weekend reading tutorials on the web and see if I could get something up and running by Monday morning. So I hit it hard. I read everything I could find, just trying to get something that worked. But I wasnt able to get it working, so I didnt get the job. But I still wanted to learn Hibernate, so I bought the book "Java Persistence with Hibernate" that everybody raves about. That book was not good for me. It seemed ponderous. It has all sorts of references to JSR white papers and stuff like that. I dont care about all that. I just wanted to find something that would help me figure out how to get my project running. I read 500 pages of that book, and I still felt confused.

So then I bought Hibernate Made Easy, and I LOVE it! It starts out with some very simple examples, so you get something working and you start to gain confidence. The first chapter is about how to set up Hibernate, and the second chapter is about testing your setup. Then he starts off with some very simple code that saves a record to the database. And then gradually he increases the complexity of the problems and the solutions until by the end of the book you're ready to solve real world problems. It's great. It's very logical and straightforward, and surprisingly, it's also fun to read. I mean, this is a book about Java persistence, but it's fun to read. How did he do that?

This book is thorough, easy to read, light-hearted, and it tackles all the difficult topics in a logical, step-by-step way. I think it's an outstanding book. After reading it I feel prepared to tackle my next interview. I feel like I can confidently say "I know Hibernate."

Thursday, July 10, 2008

Hibernate Made Easy Book Feedback from Mark Spitzer of the JavaRanch

When my book on Hiberante was released on amazon a short while ago, I was lucky enough to have Mark Spritzler from the JavaRanch to ask for a copy of the book to go over. To be honest, I was a little surprised when Mark sent me some feedback. I mean, the guys a pretty respected expert on the topic of Hibernate and ORM mapping in general, so I really don't think there was a lick of information that he could learn from the book, but he did read it, and he sent me some great feedback.

He noticed a coulple of little things that have been in thorn in my side since re-reading the original printing. One thorn was the updateAll method that calls saveOrUpdate, but doesn't really need to since the User object is loaded and subsequently changes all within the same open session. If you do that, there's no need to update, because the Hibernate Session is still keeping track of any state changes, and will commit them when the transaction is finished.

He also noticed the change from User u to User user. I made that change after about writing a third of the book, but I was worried that if I went back to the first third and did a find/replace thing, then I'd end up missing a bunch of references and the code would break. :( I do have a line that mentions the change when it first happens, but perhaps it is not enough.

Another thing he notes is that I place the annotation on the getter, not the variable. That's they way my last few project managers have requested it, and that's the way I wrote the book. But it seems the trend is actually to put the annotation on the property, not the getter. :( I'll make a note of that in the next printing of the Hibernate book.

I also think Mark's mention of disagreeing with me on HQL vs. the Criteria API is hugely important. I make a few glib remarks about HQL, but someone like Mark, who has really done alot of work in this area, knows the value of HQL. His opinion on the project should probably hold much more water than mine.

Anyways, here's his feedback. i do hope he doesn't mind me sharing the email he sent me. It's really more embarassing to me than to him. :)


"Hey Cameron, I finished reading your Hibernate book over my vacation, and got a good list for you. I had found 2 spelling errors, but I wanted to read through the book and didn't note the pages. I am also sure I saw somewhere, where you created an instance variable called "user or "u", and then later in the same code switched it around. Something like

User user = new User();
u.setPassword();

But when I went page by page through the book three times, I couldn't find it again. It might be that I was looking at the code and maybe it was just in the text part. Anyway, it might be nice to consistently use "user" or just "u" in all code that makes Users.

So some notes about my notes. I take it many reasons for things in your book it so show the basics, and just enough to not scare people off. In some cases not show them all options, but just the basic stuff.

OK, so for my notes

Around page 64-65. Basically it is about the @Id annotation. In the case of all your code, you always put the @Id on the getter. But it is also able to go on the actual field/instance variable. And based on where you put your @Id, is where you put your other Annotations, unless you use an special attribute of the annotations. I think something like access="field" or something like that.


Page 67 - In all your code you use addAnnotatedClass(), and in the book never mention that in the config file you can add one setting that will make Hibernate search the classpath for any class that has an @Entity annotation and automatically add it.

Page 76 - default field naming for ids. Correct me if I am wrong, but I was always under the impression that Hibernate will concatenate the class name with the id attribute as the default pk id field. For instance, if I have the User class with the id attribute, it would look for a user_id field as the PK.

Page 109 - JDBC and HQL variable injection with "?" I thought the first "?" in jdbc and Hibernate was the "0" position and not "1", that it was zero based?

page 117 - updateAll() method is calling the update() method in the for loop. But since the data objects were loaded in the session, then changed, that Hibernate is already maintaining those objects, and therefore a call to update() is unneccesary, as they will have update statements run at commit()

page 129 - SessionFactory singleton. Most people implement singletons with static initializers instead of the single check in the "get" method. The code as is could create two instances of the SessionFactory.

Page 190-192 - Do you want to mention @NamedQueries for when you have more than one named query declared?

Mapping Inheritence chapter - a whole big topic here. So I am saving it for last.

Page 323 - Title shows @OneToMany. Did you mean @OneToOne? also look at the text in the first paragraph there for another @OneToMany


Ok the mapping inheritence chapter. As far as exactly what is written, it is fine. But there is another view point, or perspecitve in terms of the object model that the text would not work for, and is one that is used in the JBoss Hibernate class. If you have an object model that has one super class and two direct subclasses. So a parent with two children, instead of your grand-parent/parent/child example. In the case of two children then you would find that for a database the third normal form will be the better data model to map to. Now in one or two cases the polymorphic query would be slower, in other cases the queries will be faster in this model.

I definitely enjoyed the book, and will give it a good review. Although I disagree with you on Criteria versus HQL, but I am more of a whatever will work best for the particular query. So for simple queries, I love Criteria, but once I add more tables/objects/joins, and more complex queries, give me HQL anyday over Criteria. :)

I think your book does a great job in its intention to get someone who is brand new to Hibernate, up and running quickly and understanding the basics to effectively take on the Hibernate learning curve. (I better copy/paste that into my review)

Talk to you later

Mark Spritzler"

Errata for Hibernate Made Easy: Simplified Data Persistence with Hibernate and JPA Annotations

So, I've got some great feedback from readers over the past month or so with regards to my Hibernate3 book. Not too many errors, a few typos, and lots of great suggestions. Seriously, the Java community is so awesome with regards to helping each other out. It makes the whole process very rewarding!

I'm going to just post some of the feedback here, in no particular order for now, just so I can get it out there. So, here goes!



**********************
(From TUN)
Book: Hibernate Made Easy
Page: 137
In chapter 5, the code for the improved version of the User class using HibernateUtil doesn't compile. I had to add the following line of code to work.

import

com.examscam.HibernateUtil;

Tun.

(I believe this was fixed in the second printing)


***********************************

More from Tun

Hi,
There was something in the book that made me scratch my head. I had to spend about 40 minutes to figure this out. (I am talking about the very first printing edition of Hibernate Made Easy book.)
On page 41, you recommended to install JDK 1.5 or higher. On page 75, you gave an example on compiling the User.java class using "javac -classpath "c:\_hiblib\*" User.java". What I found was that the wildcarding "*" the classpath is JDK 1.6 feature. It's not supported on JDK 1.5. Since I had JDK 1.5, it wasn't working for me. After I upgraded to JDK 1.6, it all worked fine. Just wanted to let you know.
Tun.

I still haven't figured this out for Java5...Maybe someone can give me the right compiler syntax?

***********************************
Book: Hibernate Made Easy
Edition: Very First Printing
On page 223, the code for the abstract ExamScamDAO class has the "import com.examscam.ExamScamException;" statement. Up to page 223, I couldn't find any reference or definition of com.examscam.ExamScamException. Also, the code works fine without the import statement. So I assume it's a typo.

Yup...Again, I believe I fixed this for the second printing. :( See what happens when you play around with ideas when you're writing a book. This should just be a warning, not a compile error.

***********************************
From Tun - this guy rocks!

On page 257, the code for user.jsp, on line 3 it says
contentType="text/html;
It should be
contentType="text/html"
Semicolon should be replaced with double quotes.


***********************************
On the same page,on line 10, the code is instantiating the interface UserDAO.
Currently,
UserDAO userDAO = new UserDAO;
Should be
UserDAO userDAO = new HibernateUserDAO;

user.jsp is a pretty neat example. I learned a lot. Thanks.

This is actually a REAL code error. Tun wouldn't take the $100 reward. I am sending him some signed copies of the next update, not to mention a thank you in the print as well. Great guy!
***********************************

I never promised to help deploy a web app in my Hibernate Book. I leave that to the Sevlet and JSP books out there. But Tun did provide some guidance, saying:

"I really appreciate this user.jsp example. One other thing on the example. I had to copy standard.jar and jstl.jar files to my WEB-INF/lib directory. I am not sure what I did was the standard way. But I got it working."

So, you many need the standard.jar and jstl.jar files to deploy this application to Tomcat.

"Regarding the jstl issue I had, I am running Tomcat 5.5.26. When I tried to bring up user.jsp, Tomcat complained about not being able to resolve the uri=http://java.sun.com/jsp/jstl/core. I found my solution at http://forum.java.sun.com/thread.jspa?threadID=764807&messageID=4362177."

***********************************
Amit Anand saved my but on these ones...You need to make a few changes to actually get the Inheritance Mapping to run. It's not a compile error, but it is a showstopping runtime omission.

Working through the chapter on mapping inheritance

If you use
@Id
@GeneratedValue

With
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
On the Ancestor class

Throws the following error

Cannot use identity column key generation with mapping for: com.anand.hibernatesample.domain.Parent

I got around this as follows

public Class Ancestor
{
@Id
@org.hibernate.annotations.GenericGenerator(name = "hibernate-uuid",
strategy = "uuid")

@Column(name = "ancestor_id")
private Long id;

....

}

I am Using MySQL (maybe a different version from yours) Actually, the SchemaExport throws the error when you try to run it as is from the book and I have seen various people posting this error on hibernate forums - cannot use the native Id generator with the TABLE_PER_CLASS strategy. If you paste the actual error message I pasted below and do a google search - you will see what I mean (just do a google search on

Cannot use identity column key generation with mapping for
)


***********************************
Alex Fanti was kind enought to help me with some typos in the prose:

Pg 16-80 (even) header
Pg 17 Line 1
Pg 22 PP 2 Line 4
Pg 52 PP 3 Line 4
Pg 90 PP 3 Line 1

Pg 98 Line 1
Pg 158 PP 2 Line 6
Pg 193 Line 6
Pg 196 Line 2
Pg 215 Line 2

Pg 217 Line 3-4
Pg 293 PP 3 Line 4
Pg 314 PP 2 Line 3
Pg 323 Section Header
Pg 356 Section Header

***********************************
Jim Dewberry helped me here:

I found a small typo and thought I'd pass it along in case nobody else did already.
On the last line on page 54 you spelled "compiled" as "comiled".


***********************************
Robert de B├ęsche had this great find that nobody else noticed!

In the image on page 385 (showing the database structure for chapter 20 -Advanced Mappings) of your Hibernate book there is what seems to be a strangely named property in the ‘address’ table listing. The column of ‘address’ mapping addresses to clients is named “insider_id”. I would have expected this to be “client_id” as the @JoinColumn annotation specifies in the listing on page 379? Is it an error, or am I missing something?

No, you're not missing anything Robert....That was me who messed up. Thanks!
***********************************
Jim Dewberry added some more:

I found a few little typos you might want to fix. On page 90 right underneath the "Persistent Objects" header, the sentence says "Once a JavaBean has touched by the Hibernate Session," and I think you might want to add the word "been" so that it reads "Once a JavaBean has BEEN touched by the Hibernate Session".
Also, the first sentence on line 98 says "You will also notice that I have set they type attribute" and I think you probably meant to say "set THE type attribute" instead.

Also, page 106, line 2: "It is completely up to the you" should be "It is completely up to you"
Also, page 140, line 1 "one of the thing you might have noticed" should be "one of the thingS you might have noticed"
page 163, first line of 2nd paragraph: "Once you being a transaction" should be "Once you begin a transaction"
Also, I found a small coding error. There's a missing quote on page 257. On line 3 the contentType="text/html is missing the end quote.
Also, I didnt feel like typing out all the code for creating sample data for the Criteria examples, so I wrote a little class that generates sample data. Feel free to use it or to offer it to other readers if you could just give me credit. I attached a zip file with the java code.



***********************************
Andrej didn't like my naming of banks in my example. It's good, solid, feedbac:

On page 299 of your book towards the bottom of the " public classInterest", you have:
Long wayne=new Long(99); Long mario=new Long(88);
mario is not a bank name, and I think that is what you want to describe. Should have a bankname variable, e.g, firstNationalBank etc. Same correction needed on page 300.

Sometimes, when you're up late at night, you start doing things that keep your mind interested. 88 and 99 are obviously Mario Lemiuex and Wayne Gretzky's jersy numbers, but alsa, maybe it doesn't help the learning process. I'll mark that for an update.
***********************************
Ademiju also notice the mistake on the DAO, along with a few other errors in the prose. Thanks Ademiju!

1. The most important one is on page 256/257, the fact that you have instantiated an interface.

UserDAO userdao = new UserDAO();

2. Page 274. In the last past paragraph you mentioned that foo table is the primary mapping table and bar will be the secondary but it seem to have swapped around in your sample code below it.

3. Page 146, at the start of the first Paragraph, should this say “With our” instead of “With out”?

***********************************

Well, that's it for now!

***********************************





Jim's Sample Code Class for everyone:

package com.examscam;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Random;

import org.hibernate.Query;
import org.hibernate.Session;

import com.examscam.model.User;

public class SampleData {

private static final String alphanumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private static final String[] domains = {"@Yahoo.com", "@Hotmail.com", "@Gmail.com"};
private static final String[] names = {
"Mary", "Joe", "Tom", "Sally", "Sallie", "Jim", "Tim", "Bill", "Brad", "Damian",
"Katrina", "Shelley", "Shannon", "Amie", "Cathy", "Kathy", "Elizabeth", "Blake",
"Peggy", "Sabrina", "Samantha", "Chris", "Matt", "Vince", "Bran", "Megan", "Sean",
"Jillian", "Chrissi", "Mike", "Matthew", "David", "Jeff", "Shelly", "Sherra",
"Robin", "Curtis", "Lev", "Andrew", "Richard", "Derrick"
};

public static void main(String[] args){

deleteAll();
for (int i = 0; i < 20; i++){
createSampleData();
}
}

public static void deleteAll(){
Session session = HibernateUtil.beginTransaction();

List allUsers;
Query queryResult = session.createQuery("from User");
allUsers = queryResult.list();

for (int i = 0; i < allUsers.size(); i++){
User user = (User)allUsers.get(i);
session.delete(user);
}

HibernateUtil.commitTransaction();
}


public static void createSampleData(){

User u = new User();

u.setEncryptedPassword(createPassword());
u.setRegistrationDate(createDate());
u.setLastAccessTime(createDateTime(u));
u.setLoginName(createName());
u.setPassword(createPassword());
u.setVerified(createRandomBoolean());
u.setEmailAddress(createEmailAddress(u));

Session session = HibernateUtil.beginTransaction();
session.saveOrUpdate(u);
HibernateUtil.commitTransaction();
}

private static java.util.Date createDateTime(User u){

java.util.Date accDate = generateDateTime();
java.util.Date regDate = convertCalendarToDate(u.getRegistrationDate());

while (regDate.after(accDate)){
accDate = generateDateTime();
}
return accDate;
}

private static java.util.Date convertCalendarToDate(Calendar cal){

java.util.Date date = null;
date = new Date(cal.get(Calendar.YEAR)-1900, cal.get(Calendar.MONTH), cal.get(Calendar.DATE));
return date;
}

private static java.util.Date generateDateTime(){

Random generator = new Random();
java.util.Date date = null;

int month = generator.nextInt(12) + 1;
int day = generator.nextInt(30) + 1;
int year = generator.nextInt(3);
int hour = generator.nextInt(24);
int minute = generator.nextInt(60);
int second = generator.nextInt(60);

int[] yearChoices = {2006,2007,2008};

int dateYear = yearChoices[year]-1900;

while ( (month == 2) && (day > 28) ){
day = generator.nextInt(30) + 1;
}

date = new Date(dateYear, month, day, hour, minute, second);

return date;
}

private static java.util.GregorianCalendar createDate(){
Random generator = new Random();
int days = generator.nextInt(1000);

GregorianCalendar cal = new GregorianCalendar();
cal.add(Calendar.DATE, -days);
cal.getTime();

return cal;
}

private static String createPassword(){
StringBuffer result = new StringBuffer();
Random generator = new Random();
int pos = 0;

for (int i=0; i< 6; i++){
pos = generator.nextInt((alphanumeric.length()-1));
result.append( alphanumeric.charAt(pos) );
}

return result.toString();
}

private static String createEmailAddress(User u){

Random generator = new Random();
int pos = generator.nextInt(3);

String user = u.getLoginName();
String domain = domains[pos];

return user+domain;

}

private static String createName(){

Random generator = new Random();
int sizeOfNames = names.length;
int pos = generator.nextInt(sizeOfNames);
return names[pos];
}

private static Boolean createRandomBoolean(){
Random generator = new Random();
if (generator.nextInt() % 2 == 0){
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
}

Wednesday, July 9, 2008

What is Hibernate? What is Java Persistence with Hibernate? Understanding ORM with Hibernate3...




What is Hibernate3 all about? Why use Hibernate for Object Relational Mapping?

To see the original webpage from which this blog post originates, head over to www.hibernatemadeeasy.com

What is Hibernate, you ask?

Well, there's a long answers to that, and there's short answers to that. The short and simple answer? Hibernate makes it easy to save data to, or load data from, a database.

And of course, Hibernate is Java based, and we all love Java. Java's object oriented, it's cross platform, it's fun to code, and it makes you think of that black blood of the soul: Tim Hortons Coffee. Seriously though, Hibernate is real easy to use, especially if you have a bit of a Java background. And it integrates quite naturally into your existing Java programs.


I keep hearing the term 'Java Persistence.' What does 'Java Persistence' mean?

When we write Java code, we create objects, and those objects have properties. Here's a simple piece of code. Just by looking at it, I think you can tell what the User's name and password are:

User user = new User();        //an object named user is created
user.setName("Cameron"); //name is initialized to Cameron
user.setPassword("n0tte11ing");//password is initialized to n0tte11ing

I think even the uninitiated Java programmer would recognize that we have just created a user named Cameron with a password of n0tte11ing. We see this type of object creation and property initialization in Java programs all the time. But the problem Java developers always have is figuring out how to take the data associated with the object and save it to the database. Hibernate makes the persistence of your Java objects, aka Java Persistence, easy.

Just how easy is it to persist Java objects with Hibernate?

With a magical and mystical object known as the Hibernate Session, persisting the state of your Java objects is easy. Look how readable and understandable the following code is:

User user = new User();        //an object named user is created
user.setName("Cameron"); //name is initialized to Cameron
user.setPassword("n0tte11ing");//password is initialized to n0tte11ing
Session hibernateSession = HibernateUtil.getSession();
//get the magical Hibernate session
hibernateSession.save(user); //save the user to the database!

The line of code hibernateSession.save(user); saves the state of the user instance to the database. Of course, there's a little bit of plumbing code that needs to go in there to make the whole hibernate framework work; But setting up that plumbing code really isn't that bad. Overall, Hibernate is real easy to use, fairly easy to set up, and probably the easiest way to manage the persistent state of you domain model objects.


What are JPA Annotations?
Explaining why JPA annotations are better than crummy hbm mapping files...

JPA annotations greatly simplify persistence programming with Hibernate, but to understand why they're so great, it helps to understand what we needed to do before the introduction of annotations.

Back to the Future: This Historical hibernate-mapping.xml File

Hibernate makes persisting the state of your Java objects incredibly simple. However, in order for Hibernate to know where to story your JavaBeans, or how to map the property of a JavaBean to a database column, the developer has to provide a bit of direction to the Hibernate framework. As such, people developing Hibernate based applications had to maintain an unweildly, monolithic mapping file that described how to save a given Java object to the database.

So, for example, if you had a class named Event that had three properties, one called id, one called birthday, and another property called title, you would have to add the following segment to a hibernate-mapping file:

(won't show because blogger is messing up the < and &gt tags.)











:

What's wrong with an XML mapping file?

There is nothing inherently wrong, with a mapping file, and in fact, thousands of very salacious hibernate applications that are in production use an XML mappings file, but having a big XML mapping file presents a variety of non-lethal, but certainly annoying problems, including the following:

  • information about the Java class must be maintained in an external file
  • XML isn't always easy to write
  • with lots of classes, the XML file can become unweildly and massive
  • errors in one part of the XML file can ricochet all over your Java program

Anyways, Java 5 introducted a new Java based artifact - that annotation. Basically, an annotation allows you to add detail an information about a Java class, without damaging, disturbing or changing any of the code that is actually found inside a Java class or a Java method. So, instead of using a monolithic mappings file, Hibernate with JPA annotations allows you to completely rid applications of a mapping file, and instead, you can annotate your Java classes like so:

@Entity
public class Event {
private Long id;
private String title;
private Date date;
@Id
@GeneratedValue
public Long getId() { return id; }
private void setId(Long id) {this.id = id;}
public Date getDate() {return date;}
public void setDate(Date date) {this.date = date;}
public String getTitle() {return title;}
public void setTitle(String title) {this.title = title;}
}

The @Entity, @Id and @GeneratedValue tags you see in the Event class are the JPA annotations, and they replace the neeed to describe how to persist your Java classes in an external hibernate-mappings.xml file. Instead of using an external file, each Java class maintains its own mapping information, which is much more natural, and much easier to maintain on a class by class basis. Furthermore, it makes introducing new classes, or even removing persistent classes from your domain model, much much easier.

If you're using Hibernate, and you have the ability to choose between using annotations or using a hibernate-mapping file, well, it's really not much of a choice. Always use JPA annotations if you have a choice. JPA annotations are much easier to use, easy to maintain, and will help to make your Hibernate development experience a real pleasure. :)


To see the original webpage from which this blog post originates, head over to www.hibernatemadeeasy.com

java spring cache class collection configuration database dialect download example mapping query sql tutorial xml struts xp 3 3.0 api caching cfg xml dao examples framework generator in action jdbc list one to one plugin properties tool tools training tutorials java persistence with jboss linux standby ubuntu xdoclet synchronizer computer disable enable 2 3.2 annotation annotations bag batch blob button c3p0 cascade command composite id composite key config connection criteria date delete discriminator documentation ehcache entitymanager enum fetch file filter flush formula forum hbm hbm2ddl hbm2ddl auto hql id in vista inheritance insert interceptor interview questions inverse javadoc join jpa lazy lazy loading load logging many to many many to one map mapping file merge mode named query order order by org performance problems property proxy query language reference restrictions reverse engineering save saveorupdate search select sequence session sessionfactory set shortcut show_sql source sql query stored procedure template timestamp transaction type update usertype validator version how to laptop net sf netbeans org dialect org session sleep sleep vs spring and standby vs turn off vista what is windows windows xp all 150 Help java spring apache xml ajax cache cmp j2ee s truts tomcat ejb jboss jsf maven primary key ruby on rails foreign key hibernation ibatis one to one spring framework xdoclet hql hybernate jdo many to many middlegen ojb one to many

Understanding the Inverse Attribute on a Many Mapping with Hibernate and JPA Annotations (Java Persistence API)

I actually found this post quite helpful.

JavaRanch Post on Understanding the Inverse Attribute


I am fairly new to hibernate and I've finished the tutorial here (which is great by the way). But I am still confused about the use of the "inverse" property.

My database has a many-to-many bi-directional relationship between zipcodes and notifications. A notification can be sent to many zipcodes, and a zipcode can have many notifications sent to it.

From toying with the code, I can see that if I set one side of the relationship as inverse="true"

code:















than I am unable to add a notification to a zipcode:

code:

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Notification aNotification = (Notification) session.load(Notification.class, notification_id);
Zipcode aZipcode = (Zipcode) session.load(Zipcode.class, zipcode_id);
aZipcode.getNotificationMappings().add(aNotification);
//nothing happens...no error, or update/insert
session.getTransaction().commit();



I am not sure what this really does for me. If I remove the "inverse" property on both sides (notifications and zip) I can add a zip to a notification, or a notification to a zip - no problem. But if I add the "inverse" property...it seems I am limiting myself, and I don't see the benefit. But according to the tutorial:

quote: The rules you have to remember are straightforward: All bi-directional associations need one side as inverse. In a one-to-many association it has to be the many-side, in many-to-many association you can pick either side, there is no difference.



So my questions are:
1) Do we really need to set one side of the relationship as inverse? My code is working fine (and as desired) without it.
2) If we do set it, what are the advantages? Posts: 182 | Registered: Oct 2004 | IP: Logged
Stevi Deter
ranch hand
Member # 167955

posted Thursday, April 10, 2008 9:58 AM Profile for Stevi Deter Author's Homepage Email Stevi Deter Send New Private Message Edit/Delete Post Reply With Quote James,
An excellent set of questions that really focus on understanding the guts of Hibernate.

What helps me the most is to remember what "inverse" means in this context (which means I look it up in Java Persistence in Hibernate whenever I hit a problem!).

Mapping an association as "inverse" in Hibernate tells the framework that this association is a mirror image of the association on the other side.

When you tell Hibernate a side of an association is inverse=true, you explicitly tell Hibernate *not* to synchronize that end with the database.

This is why, in your example, when you add a notification to your mappings, it doesn't persist the data -- by marking it as inverse="true", you've asked Hibernate to ignore that addition!

The utility is in minimizing/avoiding updates in cases where you want only one end to handle updates, the classic example being adding Bids to an Item in the Caveat Emptor example. You want the Item to handle the cascade of adding and deleting bids; you don't want making a change to Bids to cascade up to the item. This minimizes unnecessary updates, selects, etc.

If the code works fine without inverse, you probably don't need it. If you need to add zipcodes to notifications, and notifications to zip codes, and don't want to force only one method of adding for clarity in your code, don't worry about inverse.

--------------------

There will always be people who are ahead of the curve, and people who are behind the curve. But knowledge moves the curve. --Bill James
Posts: 265 | Registered: Mar 2008 | IP: Logged
Mark Spritzler
ranger/sheriff
Member # 9174

posted Thursday, April 10, 2008 11:17 AM Profile for Mark Spritzler Author's Homepage Edit/Delete Post Reply With Quote

quote:Originally posted by Stevi Deter:
James,
An excellent set of questions that really focus on understanding the guts of Hibernate.

What helps me the most is to remember what "inverse" means in this context (which means I look it up in Java Persistence in Hibernate whenever I hit a problem!).

Mapping an association as "inverse" in Hibernate tells the framework that this association is a mirror image of the association on the other side.

When you tell Hibernate a side of an association is inverse=true, you explicitly tell Hibernate *not* to synchronize that end with the database.

This is why, in your example, when you add a notification to your mappings, it doesn't persist the data -- by marking it as inverse="true", you've asked Hibernate to ignore that addition!

The utility is in minimizing/avoiding updates in cases where you want only one end to handle updates, the classic example being adding Bids to an Item in the Caveat Emptor example. You want the Item to handle the cascade of adding and deleting bids; you don't want making a change to Bids to cascade up to the item. This minimizes unnecessary updates, selects, etc.

If the code works fine without inverse, you probably don't need it. If you need to add zipcodes to notifications, and notifications to zip codes, and don't want to force only one method of adding for clarity in your code, don't worry about inverse.



Sweet answer.

Mark

--------------------

How to Ask Questions the Smart Way FAQ


"I believe you can have both. and sometimes, in order to have both, you need both." - Myself
Posts: 13292 | Registered: Feb 2001 | IP: Logged
sudhan maharjan
greenhorn
Member # 163699

posted Sunday, June 29, 2008 5:16 AM Profile for sudhan maharjan Email sudhan maharjan Send New Private Message Edit/Delete Post Reply With Quote this info might be quite helpful... found it in a book Hibernate Quickly

For a many-to-many bidirectional association, one end of the association must be declared as inverse. The end declared as inverse is significant because the non-inverse end will control the joing table that links the objects. Changes made to the inverse end of the association will not be persisted.

I guess, the relation might work with inverse=true as you have done before if you traced the path through another way... like aNotification.add(aZipcode) because class zipcode has inverse=true. Posts: 1 | Registered: Jan 2008 | IP: Logged
Nirmal Java
greenhorn
Member # 176347

posted Today 3:31 AM Profile for Nirmal Java Email Nirmal Java Send New Private Message Edit/Delete Post Reply With Quote inverse = true ?
================
Replace "inverse" by "ignore" and then see the result:

inverse = true means to ignore the relationship of this side
inverse = false means not to ignore the relationship of this side

In parent-child relationship, parent is one side and children are many side.

one-to-many inverse=”false”
means relationship of parent side should not be ignored. So
parent.getChildren() will be examined, child.getParent() is ignored

For the following example:
Parent parentA = getParentA();
Parent parentB = getParentB();
child = new Child();
parentA.getChildren().add(child); Will be used
child.setParent(parentB); Will be ignored Posts: 1 | Registered: Jul 2008 | IP: Logged

Sunday, July 6, 2008

Data Persistence with Hibernate and JPA

Just a quick first blog to let you know what is ahead.

I've been doing a huge amount of work with Hibernate lately, and my Book on Hibernate has been getting rave reviews and great feedback. As such, I'm planning on using this blog site to post some multimedia tutorials, updates to the book, maybe some errata (just in case there's something wrong in the book) and perhaps even some pontifications about Hibernate, JPA, EJB3, and object relational mapping (ORM) in general.

Keep posted. There's lots more to come!