Search code examples
sessionnhibernateflushdirty-data

NHibernate: How to know if, on Flush() SQL will be sent?


I'm a bit puzzled with the NHibernate's IsDirty() method.

Directly after getting a (very large) complex object from my database, NHibernate's ISession.IsDirty() gives 'true'.

IFacadeDAL fd = new FacadeDAL();
// Session's not dirty

IProject proj = fd.GetByID<IProject, string>("123611-3640");
// Session is dirty

However, if i call Commit() like so:

using (ITransaction trans = Facade.Session.Transaction)
{
    trans.Begin();
    Facade.Session.Save(entity);
    trans.Commit();
    return true;
}

this results in no sql (exept for "exec sp_reset_connection").

I have read that due to 'mapping-choices' you can get "ghosts" in your session (causing the session to say it's dirty), but wouldn't it then also try to update something? Also, if this is caused e.g. by "converting" an sql bit to a c# bool i don't think i can change it... (no clue if that could be a cause for ghosts, though).

Update 2: There are several (sql server) views and tables involved here. This is the (very) simplified class:

public class Project : IProject
{
    private string id;
    private List<IPlantItem> plantItems;

    public Project() { }

    public virtual string ID
    {
        get { return id; }
    }

    public virtual IEnumerable<IPlantItem> PlantItems
    {
        get { return plantItems; }
    }
}

'PlantItem is being stored in a table. So i expect when i change anything in a PlantItem, IsDirty should change to 'true'.

My question is: is there a way to check if the session at that point, on flush() (or in my case on commit() for that matter) would generated actual sql statements? And if not: is there another way of (manually) storing some sort of a snapshot of the session to compare the current session to?

Update 1: I should really also mention these aspects:

  1. that my FlushMode is set to 'None'.
  2. that the underlying data of 'IProject'-object itself is based on a sql-view and therefore has most properties in the mapping set to update="false"
  3. that when i actually change something in an object and use the same method for saving, sql update statements are being sent (and thus all is committed just fine)

Solution

  • In my experience Ghosts can be caused by the database being a nullable int and the mapping an ordinary int.

    When the entity gets hydrated the nullable db int is converted to zero and hence it is now dirty.

    Another way to get dirty records is by specifying a wrong type in the XML mapping, e.g.

    public enum Sex
    {
     Unspecified,
     Male,
     Female
    }
    ...
    public virtual Sex Sex { get; set; }
    

    and specify an int in the mapping.

     <property name="Sex" type="int"/>
    

    See this link to test your mappings which explains in more details.