Eager Fetch or Fetch Join?

Ayende has a brilliant idea to fix the famous NHiberate select N+1 problem by using Eager Fetch in Dao operation, either ISession.CreateQuery() or ISession.CreateCriteria(). The same solution can be found in Chapter 8 of the new published book “NHibernate in Action”.

This works great, for one-to-many association (I noticed that it only can reach to one level of association),  for one-to-one, or many-to-one,  the easier way is, just change the fetch option in many-to-one mapping from default ‘select’ to ‘join’.

I tested my app, it improved performance a lot! Maybe this setting conflicts with lazy-load?

From Hibernate doc,

With fetch="join" on a collection or single-valued association mapping, you will actually avoid the second SELECT (hence making the association or collection non-lazy), by using just one “bigger” outer (for nullable many-to-one foreign keys and collections) or inner (for not-null many-to-one foreign keys) join SELECT to get both the owning entity and the referenced entity or collection. If you use fetch=”join” for more than one collection role for a particular entity instance (in “parallel”), you create a Cartesian product (also called cross join) and two (lazy or non-lazy) SELECT would probably be faster.

About these ads

Lazy-load conflicts with Property-ref in Many-to-One Mapping

Just figured this problem out, I had to remove the property-ref tag from my ‘Many-to-One’ mapping xml file to enable lazy-load working. I am using SQLServer 2005.

From Hibernate forum, some people are having the same problem, but it’s in Hibernate 3 project.

Another thing for lazy-load, all properties in entity/domain object need to set to ‘virtual’.

What’s virtual? Explanation from http://www.dotnettreats.com/tipstricks/oopconcepts2.aspx:

Virtual keyword

The virtual keyword allows polimorphism too. A virtual property or method has an implementation in the base class, and can be overriden in the derived classes.

To create a virtual member in C#, use the virtual keyword:

public virtual void Draw()

To create a virtual member in VB.NET, use the Overridable keyword:

Public Overridable Function Draw()

NHibernate and Stored Procedure, Part2, dealing with orginal values

In part1, I can easily add those original values in the hbm mapping xml files. This works OK for web forms, and also no problem for one time update in win forms. But when I tried to make a repeatable update in win forms, the problem appears.

The original values in Entity objects doesn’t sync! When I called a DAO.commit(), all the changes have been made into database, and the changed columns/properties also still kept in entity objects, you think those original properties will be refreshed? No, not until you clean up the NHiberate cache manually.

Object: ID,
property: originalvalue (1)
property: realvalue (1)

Set realvalue = 2, then call Dao.CommitChanges()

Object: ID,
property: originalvalue (1) {This didn’t update! Still keep the previous original value, should be the current/original value which is 2.}
property: realvalue (2)

The solution I got is, after Dao.CommitChanges(), do a cache clean up manually.

myEntityDao.StartTransaction();
myEntityDao.SaveOrUpdate(view.MyEntityToUpdate);
myEntityDao.CommitChanges();

myEntityDao.Evict( view.MyEntityToUpdate );

This made my winForm repeatable update working. An extra work is, I have to recall the initview() in UI layer, because UI needs to re-load this updated object from Dao after evict().

Again, this is a win form only issue, web form doesn’t have this problem because each page is reloaded after every commit.