2

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)
Hadzjie
  • 63
  • 6
  • Just to be sure: is your `FlushMode` set to **NONE**? and if it is: why you are not calling `session.Flush()` before `trans.Commit()`? None means, that Flush will never be called. Never, neither on a commit. – Radim Köhler May 14 '14 at 13:03
  • @Radim: Thnks Radim, but i use nh ITransaction in this case, so according to this: http://nhforge.org/doc/nh/en/index.html#manipulatingdata-endingsession , i wouldn't have to. Also, every other functionallity works just fine (committing changes and stuff). – Hadzjie May 14 '14 at 13:13
  • Could you have a ghost mapping that makes the session think it's dirty, but since you have it mapped as `update="false"`, no updates get sent? – dotjoe May 14 '14 at 15:42
  • Dirty hack to stop any updates to a view (I suspect you have a ghost) is to add `` to your class mappings – Rippo May 14 '14 at 18:24
  • Why is setting mutable to false a dirty hack? I would suggest looking at the ghostbuster test and including it in your test suit. http://joseoncode.com/2010/02/05/nhibernate-ghostbuster-version-1-1/ – Fran May 14 '14 at 20:27
  • Yes word hack is a little out of context, if you can't find the issue then it would be a hack. If you can find the issue great, then turn on `mutable=false` at this point it wouldn't be a hack. Either way set `mutable=false` for view mappings is a good idea. This link may also help you determining whether you have a ghost http://nhforge.org/blogs/nhibernate/archive/2008/10/20/how-test-your-mappings-the-ghostbuster.aspx – Rippo May 15 '14 at 05:42
  • The issue isn't 'the view-part' (i'll update the question).. I want to distinguish between: there **will** be sql sent and there **won't** be sql (to send). – Hadzjie May 15 '14 at 06:22
  • @Rippo I'm pretty sure there are 'ghosts'.. Was hoping to not need to go through +60 mappings one by one... However, the solution (Ghostbuster) you suggested looks promising! I'll check it out – Hadzjie May 15 '14 at 06:39
  • Ah I see *tables and views* :), 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. Or by specifying a wrong type in the XML mapping. Good luck! – Rippo May 15 '14 at 06:49
  • @Rippo With my version of VS i cant get that code to work (need VisualStudio-namespace for that and that in turn needs VS201x Premium or higher; i'm using VS2013 Prof.). Clear though, that i'll have to go through my mappings. Why don't you drop your comment as 'Answer' so i can mark it? – Hadzjie May 15 '14 at 12:33

2 Answers2

1

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.

Rippo
  • 22,117
  • 14
  • 78
  • 117
0

If some of your entities is dirty - and therefore the ISession is dirty - they you have a mismatch between the properties and the database. For example, imagine you have a column in a table that is nullable, but in your code it is set as not null (an int, for example). NHibernate will consider it dirty, because its current value (0 in case of an integer) is different from the value that came from the db (null). Look for "Ghost properties NHibernate" in Google.

Ricardo Peres
  • 13,724
  • 5
  • 57
  • 74