Domanda

I am looking for help on an issue with NHibernate which has been bugging me for a while now. Long story short:

I’m looking for a way to, in the first level cache, “reset” a property on an entity each time I do an update or an insert.

What I want to achieve is that the property in question will always be considered to be dirty by NHibernate when using dynamic update or insert.

The backstory for this is that I know that, if the transaction was successful, the column that I want to “reset” will be set to Null in the database by a trigger. On the flip side, the first level cache does not know this, and thus NHibernate will think that the property was not updated when I set it to the same value as I did on the previous update/insert. The catch is that my trigger is dependent on this value being set. The resulting mess is that if I want to use dynamic update or insert I’m only able to update/insert an entity once without “refreshing” it afterwards (which I really don’t want to do).

Tips or help would be much appreciated, because I’ve really hit a wall here

È stato utile?

Soluzione

NHibernate provides many places for extension. Among them is the Session IInterceptor. There is documentation with many details:

http://nhibernate.info/doc/nh/en/index.html#objectstate-interceptors

In this case, we can create our custom one, which will be observing our entity (for example Client) and a property which must be updated every time (for example Code). So our implementation could look like this:

public class MyInterceptor : EmptyInterceptor
{
    public override int[] FindDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types)
    {
        var result = new List<int>();

        // we do not care about other entities here
        if(!(entity is Client))
        {
            return null; 
        }

        var length = propertyNames.Length;

        // iterate all properties
        for(var i = 0; i < length; i++)
        {
            var areEqual = currentState[i].Equals(previousState[i]);
            var isResettingProperty = propertyNames[i] == "Code";

            if (!areEqual || isResettingProperty)
            {
                result.Add(i); // the index of "Code" property will be added always
            }
        }

        return result.ToArray();
    }
}

NOTE: This is just an example! Apply your own logic for checking the dirty properties.

And we have to wrap Session this way:

var interceptor = new MyInterceptor()
_configuration.SetInterceptor(interceptor);

And this is it. While Client is marked as dynamic-update, the property Code will always be set as dirty

<class name="Client" dynamic-update="true" ...
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top