2

When I access to PreUpdateEvent, I get the entity with the updated data.
I assumed that pre update will give me the data before the update in the db.

preUpdateEvent.Entity - gives the new data. preUpdateEvent.State - gives the new data.

// Even when I go to the database and ask the persisted entity, 
//  I get it with the changes.
preUpdateEvent.Session.Get(typeof(preUpdateEvent.Entity), preUpdateEvent.Entity.Id);

How do I access the persisted entity in OnPreUpdate(PreUpdateEvent preUpdateEvent) so I can audit it to the Audit table?

UPDATE

public bool OnPreUpdate(PreUpdateEvent preUpdateEvent)
{
    var persisted = preUpdateEvent.Session.Merge(preUpdateEvent.Entity);
    return false;
}

So var persisted after the merge has the new data.
I want persisted to have the old data(pre update).

SexyMF
  • 10,657
  • 33
  • 102
  • 206

2 Answers2

3

The PreUpdateEvent Listener gets called like this

bool OnPreUpdate(PreUpdateEvent @event); 

and the complete information about the entity is passed as the @event parameter, which is of type class PreUpdateEvent. So we do have access properties:

/// <summary> The entity involved in the database operation. </summary>
public object Entity { get; }
/// <summary> The id to be used in the database operation. </summary>
public object Id { get; }
/// <summary>
/// Retrieves the state to be used in the update.
/// </summary>
public object[] State { get; }
/// <summary>
/// The old state of the entity at the time it was last loaded from the
/// database; can be null in the case of detached entities.
/// </summary>
public object[] OldState { get; }

There are all information we can get, latest changes (State) and previous values (OldState)

In this phase (event) we cannot call the session.get() ... because there is already "the updated" object. Session would NOT in this case in target the DB.

As the comment says: the OldState, could be NULL if the object comes from external world (client, service layer) and is passed to session via Update(). To avoid this, we can call session.Merge(ourInstance) which will fix lot of issues. See: 9.4.2. Updating detached objects

EXTEND: How does the OldState work?

1) Either we are loading object via sessin.GetById(id). Session has hands on it, while we are amending that instance. Finally, we call session.Flush() to do UPDATE statement in DB. In this case, NHibernate does have everything under its control... the OldState is properly filled.

2) Or we do recieve data from external (not session) world, represented by detached instance. In this case, NHibernate was not able to track changes. It only has the latest information passed via session.Update(instance), and on Flush() it does trigger the PreUpdate event, but without the old state.

In that case, we can call session.Merge(instance) instead of Update() and NHibernate will load the object from DB (and therefore will have its previous values), update them with the latest settings coming with the merging instance, and trigger the PreUpdate event with full info.

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Hi, thanks, if I look at this tread: http://stackoverflow.com/questions/867341/nhibernate-difference-between-interceptor-and-listener it says that iterceptors are kind of legacy... So If I stay at the listeners. I see that the OldState is null. isnt there anyway to to get the persisted entity inside onpreupdate? thanks – SexyMF Jan 18 '14 at 04:50
  • No no ... the Merge must be called at place, where you originally call Update! This is too late... In fact, the Merge should replace the Update... the session.Flush() *(later)* will cause the `OnPreUpdate` event to be fired... and OldState to be populated – Radim Köhler Jan 18 '14 at 05:35
  • So there is no way to get the old state inside OnPreUpdate? – SexyMF Jan 18 '14 at 05:37
  • +1. Ok, I have made my main Save method to use Merge. and I see that the oldState is now available. I have 2 questions though. 1) How changing from Save to Merge is going to affect my application? 2) how can I convert OlsState to my strong typed entity? thanks again... – SexyMF Jan 18 '14 at 07:14
  • Add 2) How to convert object to your strongly typed... it is really upon you ;) there is no built in solution... To give the answer to the first I will tell you my story: I do always call Get(id) and bind this. So all is in place out of the box. The Merge is doing in fact the same.. so not so many side effect.. except it could be later hard to understand why you did not used Update ;) ... Honestly, I created own not NHibernate mechanism to track changes. From my point of view, it is the Business feature, and does not belong to Data layer.. but it is different and large story ;) – Radim Köhler Jan 18 '14 at 07:23
0

Maybe create new session and merge object in this new session, and you will get OldState

Quynh Nguyen
  • 61
  • 1
  • 2