3

Using fluent NHibernate I have a property on a class mapped using Version

Version(x => x.Version);

When I save the object, the Version property gets incremented in the database as I would expect, but the value of the property on the object only seems to change sometimes.

using (var tx = session.BeginTransaction())
{
    session.Merge(item);
    tx.Commit();

    item.Version;  // Sometimes this is still 1, when I expect it to be 2.
}

The problem is then that if it remains as 1 and I make more changes and save again I get a StaleObjectStateException.

What's weird is that sometimes it works fine and the item.Version value does get correctly incremented, but I can't figure out the difference between the cases where it does and the cases where it doesn't.

I've tried searching but can't seem to find any documentation on this. Can anyone explain what NHibernates expected behaviour is with the Version mapping?

[NHibernate version 2.1.2]

Simon P Stevens
  • 27,303
  • 5
  • 81
  • 107

3 Answers3

2

From the ISession.Merge documentation:

Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session.

So, it will not modify item.

(I might add I have never used Merge in my apps. You might want to review how you are dealing with attached and detached entities)

Diego Mijelshon
  • 52,548
  • 16
  • 116
  • 154
  • That's interesting because it seems to work sometimes. The initial creation works and Version gets set to 1, then it's always the first update that fails to set Version to 2. Once I reload the object, subsequent updates all seem to increment the version automatically. – Simon P Stevens Jun 10 '11 at 14:56
  • (Oh, I forgot to mention. It's using NHibernate version 2.1.2) – Simon P Stevens Jun 10 '11 at 15:02
  • @SimonPStevens: I don't know about this specific issue, but 2.1.2 has been unsupported for a while and there are have been a few Merge-related changes. I suggest that you upgrade. – Diego Mijelshon Jun 10 '11 at 15:24
  • Unfortunately updating isn't an option at the moment. It's in the plan for the next release, but it can't be done right now. – Simon P Stevens Jun 10 '11 at 15:46
1

Did you try

item = session.Merge(item);
tx.Commit();

?

Meligy
  • 35,654
  • 11
  • 85
  • 109
  • [Sorry, forget that last comment]. This does work. Have you got any idea why this is only needed sometimes. Using my original code, the initial creation works and Version gets set to 1, then it's always the first update that fails to set Version to 2. Once I reload the object, subsequent updates all seem to increment the version automatically. Any idea why it is I need to use the returned object only on the second save? – Simon P Stevens Jun 10 '11 at 15:22
  • Do you have any chaching involved? If not, can you show how you open the transaction? Do you do anything with FlushMode? Answers to those can help on why it works sometimes. – Meligy Jun 10 '11 at 15:31
  • Nothing is being done with FlushMode. We're just doing "using (var tx = session.BeginTransaction())" to open the transaction. I'll have to look into the Caching in more detail before I can explain that part. I'll ask a new question if I can't figure it out from here. Thanks for the help. – Simon P Stevens Jun 10 '11 at 15:58
0

You need to flush the session before the updated version will propagate up to your entities. Unless you flush the session, you are responsible for keeping the entities up to date yourself.

You should TYPICALLY let the session flush on its own when its closed. However, in some instances where you rely on database updates that happen via nhibernate and not settings you make to the entity itself, you might need to flush the session yourself after a commit. In this case be aware that when you flush the session ANY entities that are dirty will be committed. This may not be desirable so be sure that the scope is very limited.

Fourth
  • 9,163
  • 1
  • 23
  • 28
  • Thank you. What's the impact of flushing a session? (The application is large and I want to be careful not to have any impact on other areas. I know this session object is being used in multiple places). And should I flush before or after the commit? – Simon P Stevens Jun 10 '11 at 14:24
  • modified my answer to expand on when to flush – Fourth Jun 10 '11 at 14:28
  • According to [this answer](http://stackoverflow.com/questions/43320/nhibernate-isession-flush-where-and-when-to-use-it-and-why/43567#43567) the tx.Commit() flushes the session and commits the transaction automatically. (Due to this apps architecture the Session object is kept open for quite long periods of time. For better or worse there isn't really an option to change that at this stage. I'm not sure if that makes a difference to anything) – Simon P Stevens Jun 10 '11 at 14:36
  • Ok, I've tried this now and it still doesn't work. I tried calling session.Flush() after the commit and it makes no difference. It still doesn't update the version value on the item being saved. (The initial creation works and Version gets set to 1, then it's always the first update that fails to set Version to 2. Once I reload the object, subsequent updates all seem to work correctly. – Simon P Stevens Jun 10 '11 at 14:50
  • (Oh, I forgot to mention. It's using NHibernate version 2.1.2) – Simon P Stevens Jun 10 '11 at 15:02