Mask properties from dirty check - nhibernate

I have a column in all my tables called LoggedInPersonID. To avoid cluttering mapping code, an Nhibernate Interceptor overrides OnFlushDirty and OnSave to assign the LoggedInPersonID property automatically.
If LoggedInPersonID is the only property changed, I consider the entity clean. At the moment Nhibernate (rightfully) considers the entity to be dirty.
Does any mapping construct exist to escape a property from Nhibernate's dirty check, while still including the column in any inserts/updates?
Alternatively, I have considered implementing the IPreUdateEventListener interface and use the OnPreUpdate event to check whether the only difference between OldState and State is in the property LoggedInPersonID, and cancel the update if that is the case. Would that be a valid approach?

I think if you already change the property in OnSave, the dirty check will come after, and finally OnFlushDirty will occur, when it is already decided. At least if you (unnecessarily) call Save() or SaveOrUpdate() on your object, although it is not a newly created one.

Simplier case
I would rather try to avoid setting LoggedInPersonID if the entity is not dirty. I am not comfortable with cancelling the update from IPreUdateEventListener: a lot of other processing still occurs, like second level cache updating, and other PostUpdate processing.
OnFlushDirty xml doc states:
Called when an object is detected to be dirty, during a flush.
So this means NHibernate considers your object to be dirty even before you have set its LoggedInPersonID.
You should probably check that in your interceptor with a conditional break-point to stop only on your entity type having troubles, and check if there is already some other changes between currentState and previousState before your code affects its LoggedInPersonID.
Maybe have you by example some other logic elsewhere which has already set LoggedInPersonID.
Harder case
But checking NHibernate code, it could be a bit muddier. It looks to me like OnflushDirty could be called on entities which might be dirty. (And maybe this "might be dirty" is caused by what I had suspected in my answer on your previous question.)
I such case, you should do your own dirty check inside your interceptor. You may do the dirty check in your OnFlushDirty, but then NHibernate will still do its own, causing the dirty check to be done twice. To avoid dirty checking twice each entity, you need then do your first idea: evicting LoggedInPersonID from the dirty check if this is the only dirty property.
NHibernate dirty check implementation is not trivial. Better reuse it than coding your own dirty check. But this need adding some code to your interceptor. (Done with the help of this blog on NHibernate.info.)
using NHibernate;
using NHibernate.Type;
using NHibernate.Proxy;
...
public class LoggedInPersonIDInterceptor : EmptyInterceptor
{
...
// your previous code handling the setting of LoggedInPersonID
...
private ISession _session;
public override void SetSession(ISession session)
{
_session = session;
}
public override int[] FindDirty(object entity, object id,
object[] currentState, object[] previousState,
string[] propertyNames, IType[] types)
{
var sessionImpl = _session.GetSessionImplementation();
var persistenceContext = sessionImpl.PersistenceContext;
var entry = persistenceContext.GetEntry(entity);
if (entry == null)
{
// The blog post try to handle proxy case but that part looks
// buggy to me. If you do not need to handle proxies, just let
// default implementation do the job by returning null here.
return null;
}
var persister = sessionImpl.Factory.GetEntityPersister(entry.EntityName);
var dirtyPropertiesIndexes = persister.FindDirty(currentState,
previousState, entity, sessionImpl);
// Probable superfluous null check...
if (dirtyPropertiesIndexes == null || dirtyPropertiesIndexes.Length != 1)
{
return dirtyPropertiesIndexes;
}
if (propertyNames[dirtyPropertiesIndexes[0]] == "LoggedInPersonID")
{
// return empty array for telling that nothing has changed
return new int[] {};
}
return dirtyPropertiesIndexes;
}
}
Side note : I have seen in your other question revisions your were testing on propertyNames[i].ToLower() == "loggedinpersonid". If you need that, I generally prefer do that this way : StringComparer.OrdinalIgnoreCase.Equals(propertyNames[i], "LoggedInPersonID"). This avoid messing up while manually lower-casing the property name.
Other solution
Maybe this other way I found later would be easier.

Related

Proxying NHibernate Objects with Castle DynamicProxy swallows NH-Functionality

I'm doing things considered horrible by some lately, but I personally enjoy this kind of experiment. Here's a telegraph style description:
Use NH to fetch data objects
Each DataObject is wrapped by a CastleDynamicProxy
When Properties decorated with Custom Attributes are queried, redirect to own code instead of NHibernate to get Returnvalue.
Object creation / data fetch code
Objects=GetAll().Select(x=>ProxyFactory.CreateProxy<T>(x)).ToList();
public IList<Person> GetAll()
{
ISession session = SessionService.GetSession();
IList<Person> personen = session.CreateCriteria(typeof(Person))
.List<Person>();
return personen;
}
The Proxy generation Code:
public T CreateProxy<T>(T inputObject)
{
T proxy = (T)_proxyGenerator.CreateClassProxy(typeof(T), new ObjectRelationInterceptor<T>(inputObject));
return proxy;
}
The Interceptor used is defined like so:
public class MyInterceptor<T> : IInterceptor
{
private readonly T _wrappedObject;
public MyInterceptor(T wrappedObject)
{
_wrappedObject = wrappedObject;
}
public void Intercept(IInvocation invocation)
{
if (ShouldIntercept(invocation)) { /* Fetch Data from other source*/ }
else
{
invocation.ReturnValue = invocation.Method.Invoke(_wrappedObject, invocation.Arguments);
}
}
public bool ShouldIntercept(IInvocation invocation)
{
// true if Getter / Setter and Property
// has a certain custom attribute
}
}
This works fine in an environment without NHibernate (creating objects in code, where the Object holds its own data).
Unfortunately, the else part in the Intercept method seems to leave NHibernate unfunctional, it seems the _wrappedObject is reduced to it's base type functionality (instead of being proxied by NHibernate), so all mapped Child collections remain empty.
I tried switching from lazy to eager loading (and confirmed that all SQL gets executed), but that doesn't change anything at all.
Does anybody have an idea what I could do to get this back to work?
Thanks a lot in advance!
I found out that what I do is partially wrong and partially incomplete. Instead of deleting this question, I chose to answer it myself, so that others can benefit from it as well.
First of all, I have misunderstood the class proxy to be an instance proxy, which is why i stored the _wrappedObject. I needed the Object to perform invocation.Method.Invoke(_wrappedObject, invocation.Arguments), which is the next mistake. Instead of doing so, I should have passed the call on to the next interceptor by making use of invocation.Proceed().
Now, where was that Incomplete? NH seems to need to know Metadata about it's instances, so I missed one important line to make NH aware that the proxy is one of its kin:
SessionFactory.GetClassMetadata(entityName).SetIdentifier(instance, id, entityMode);
This only works in an NHibernate Interceptor, so the final product differs a bit from my initial one...Enough gibberish, you can see a very very comprehensible example on this on Ayende's website. Big props for his great tutorial!

NHibernate: Is there a way to work out if an object is persisted or not?

I was wondering if there is actually an existing way to work out if an object is persisted yet or not? For instance an IsPersisted(object obj) method...
Checking the identifier for an empty value would work I'm sure, but I haven't fully thought this through and just wanted to be sure there wasn't something I was missing.
Thanks,
Tony
This is the entity persister's responsibility, so I'd let it figure it out instead of manually checking the unsaved-value:
public bool? IsPersisted(object obj, ISession session)
{
var sessionFactoryImpl = (ISessionFactoryImplementor)session.SessionFactory;
var persister = new SessionFactoryHelper(sessionFactoryImpl).RequireClassPersister(obj.GetType().AssemblyQualifiedName);
return !persister.IsTransient(obj, (ISessionImplementor)session);
}
The entity persister does a few more things than just checking the unsaved-value, like checking the version and the second-level cache. And it seems that it's not always possible to find out if it's transient (it returns bool?).
Checking the id against the unsaved-value is a good way. That's what the session.SaveOrUpdate method uses to decide whether to emit an INSERT or UPDATE statement.
I wrote the following ISession extension, which seems to work. If you've got something better, I'd be happy to see it.
public static bool IsNewEntity(this ISession session, object entity)
{
if (entity == null) return false;
ISessionImplementor sessionImpl = session.GetSessionImplementation();
IPersistenceContext persistenceContext = sessionImpl.PersistenceContext;
EntityEntry oldEntry = persistenceContext.GetEntry(entity);
return oldEntry == null;
}
NHibernate potentially looks at three different properties to see if an entity is persisted. In most cases checking the Id against the unsaved-value is sufficient. If the Id is assigned, a Version or Timestamp property will be checked.
Id - this works if the id is not assigned.
Version - if present and if the id is assigned.
Timestamp - if present and if the id is assigned.

Why both NHibernate OnPreInsert and OnPreUpdate methods get called for an object

I use the NHibernate OnPreInsert and OnPreUpdate events in a PreSaveEventListener to set the CreatedDate and ModifiedDate of my entities. The problem is, there are two entities for which both events get triggered when I first create them. This causes an issue because the entity state does not get saved after the OnPreInsert event, so the OnPreUpdate event operates on a whole new entity state and my CreatedDate never gets set (defaults to 01/01/0001).
At first, I thought this was because my code that was initiating two SaveOrUpdate calls back to back before the end of the transaction. Sure enough, I found some code to this effect. But then I realized this was still happening for the other entity. So far as I can tell, only these two entities have this issue. I temporarily solved the problem by setting the CreatedDate in their constructors, but I want to avoid this.
Here's my structure:
Business entity (an abstract class that has two concrete joined-subclasses)
BusinessContact entity with a Many-To-One relationship with Business
EDIT: I have recently realized that it's also happening on one other object (InvoiceLineItem), but not a near identical object (BillLineItem) instantiated and used in near identical ways. Seems rather arbitrary.
Has anyone seen this before?
Here's the event listener code:
public class PreSaveEventListener : IPreInsertEventListener, IPreUpdateEventListener {
public bool OnPreInsert(PreInsertEvent #event) {
EntityWithGuidId entity = #event.Entity as EntityWithGuidId;
if (null != entity) {
var createdDate = DateTime.Now;
var modifiedDate= DateTime.Now;
Set(#event.Persister, #event.State, "CreatedDate", createdDate);
Set(#event.Persister, #event.State, "ModifiedDate", modifiedDate);
entity.CreatedDate = createdDate;
entity.ModifiedDate = modifiedDate;
}
return false;
}
public bool OnPreUpdate(PreUpdateEvent #event) {
EntityWithGuidId entity = #event.Entity as EntityWithGuidId;
if (null != entity) {
var modifiedDate= DateTime.Now;
Set(#event.Persister, #event.State, "ModifiedDate", modifiedDate);
entity.ModifiedDate = modifiedDate;
}
return false;
}
private void Set(IEntityPersister persister, object[] state, string propertyName, object value) {
var index = Array.IndexOf(persister.PropertyNames, propertyName);
if (index == -1)
return;
state[index] = value;
}
}
Event listeners caused a lot of different issues in my project and many of them doesn't make sense to me. I think your issue can be caused in case when NHibernate really updates your entity after it created. NHibernate can update version of entity or set some id (or guid) for it. Can you put here mapping of issued entity? I also will suggest you to look at sql queries in profiler.
I actually ran into this, there is a chance it may be the same issue.
I implemented my own StringTrimEnd typehandler that did just that, trimmed the end of strings before inserting into the database, or after retrieving them.
Well, I implemented the Equals method wrong and it returned false for Equals(object x, object y) when x and y where null.
Therefore when I created a new object with a null string on it, it compared the loaded value (null) with the current value (null) and decided an update was needed (as well as the insert).
Maybe this will help someone out at some point.
You have nullable field in DB which wasn't marked as nullable in NH

NHibernate: is there a way to mark an object as NOT dirty?

I have a situation where I need to load part of an object graph using custom SQL (for performance reasons). So I load up this collection using my custom SQL (ISession.CreateSQLQuery()) and then I assign that list to a property on another entity object.
The problem is that when I assign the list to the property, it makes that entity dirty along with all of the objects in the list, so when I go to save the object, it does hundreds of queries to save the entire list. Is there a way that I can specify that an object is NOT dirty (after I load it up myself)?
(Yeah, I know I could turn off cascade="save-update", but I really don't want to have to do that if I can avoid it.)
I think there is a functionality to evict an entity.
That means it is not connected to NHibernate anymore.
UPDATED after Jon's various comments:
If you want NHibernate to manage the object, ie detect if it is dirty, then keep it managed.
If not, Evict() it, it won't be managed. You can still save it manually and so on, it's just that it won't be done automatically for you.
I don't see any middle ground, between automatic and manual...
Note that you can still persist in various ways, like saving manually the parent entity, a Set of child entities and so on... Many things are still possible.
Expanding on KLEs answer, I would:
Evict() the parent entity
Load the child list
Attach the list of children to the parent entity
Merge() the whole thing back into nHibernate
At that point I believe that NHibernate will recognize everything as clean.
Can you just remove the property you use to store this manually fetched data from NHibernates tracking?
Assuming that you are not persisting the property that the list is assigned to, you can remove that property from the NHibernate mapping. I haven't tested this, but my expectation is that assigning to that property would not cause IsDirty() to return true.
EDIT: Ok, try try this. Load the object from an IStatelessSession, call your custom SQL and assign the property. Then Lock the object into a new ISession and continue working with it. I think the Lock will cascade to child objects if your cascade setting is all or all-delete-orphan. If Lock does not cascade then you will have to manually walk the object graph.
I don't remember where I got this from, but I have a class of Session extensions, one of which is this:
public static Object GetOriginalEntityProperty(this ISession session, Object entity, String propertyName)
{
ISessionImplementor sessionImpl = session.GetSessionImplementation();
IPersistenceContext persistenceContext = sessionImpl.PersistenceContext;
EntityEntry oldEntry = persistenceContext.GetEntry(entity);
if ((oldEntry == null) && (entity is INHibernateProxy))
{
INHibernateProxy proxy = entity as INHibernateProxy;
Object obj = sessionImpl.PersistenceContext.Unproxy(proxy);
oldEntry = sessionImpl.PersistenceContext.GetEntry(obj);
}
if (oldEntry == null) // I'm assuming this means the object is transient and that this is the way to treat that
return false;
String className = oldEntry.EntityName;
IEntityPersister persister = sessionImpl.Factory.GetEntityPersister(className);
Object[] oldState = oldEntry.LoadedState;
Object[] currentState = persister.GetPropertyValues(entity, sessionImpl.EntityMode);
Int32[] dirtyProps = persister.FindDirty(currentState, oldState, entity, sessionImpl);
Int32 index = Array.IndexOf(persister.PropertyNames, propertyName);
Boolean isDirty = (dirtyProps != null) ? (Array.IndexOf(dirtyProps, index) != -1) : false;
return ((isDirty == true) ? oldState[index] : currentState[index]);
}
If you get the original value using this method and assign it to the persistent property it will no-longer be dirty.
You could use an interceptor and then override the FindDirty method.

Encapsulation within class definitions

For example, do you use accessors and mutators within your method definitions or just access the data directly? Sometimes, all the time or when in Rome?
Always try to use accessors, even inside the class. The only time you would want to access state directly and not through the public interface is if for some reason you needed to bypass the validation or other logic contained in the accessor method.
Now if you find yourself in the situation where you do need to bypass that logic you ought to step back and ask yourself whether or not this need betrays a flaw in your design.
Edit: Read Automatic vs Explicit Properties by Eric Lippert in which he delves into this very issue and explains things very clearly. It is about C# specifically but the OOP theory is universal and solid.
Here is an excerpt:
If the reason that motivated the
change from automatically implemented
property to explicitly implemented
property was to change the semantics
of the property then you should
evaluate whether the desired semantics
when accessing the property from
within the class are identical to or
different from the desired semantics
when accessing the property from
outside the class.
If the result of that investigation is
“from within the class, the desired
semantics of accessing this property
are different from the desired
semantics of accessing the property
from the outside”, then your edit has
introduced a bug. You should fix the
bug. If they are the same, then your
edit has not introduced a bug; keep
the implementation the same.
In general, I prefer accessors/mutators. That way, I can change the internal implementation of a class, while the class functions in the same way to an external user (or preexisting code that I dont want to break).
The accessors are designed so that you can add property specific logic. Such as
int Degrees
{
set
{
_degrees = value % 360;
}
}
So, you would always want to access that field through the getter and setter, and that way you can always be certain that the value will never get greater than 360.
If, as Andrew mentioned, you need to skip the validation, then it's quite possible that there is a flaw in the design of the function, or in the design of the validation.
Accessors and Mutators are designed to ensure consistency of your data, so even within your class you should always strive to make sure that there's no possible way of injecting unvalidated data into those fields.
EDIT
See this question as well:
OO Design: Do you use public properties or private fields internally?
I don't tend to share with the outside world the 'innards' of my classes and so my internal needs for data (the private method stuff) tends to not do the same sort of stuff that my public interface does, typically.
It is pretty uncommon that I'll write an accessor/mutator that a private method will call, but I suspect I'm in the minority here. Maybe I should do more of this, but I don't tend to.
Anyway, that's my [patina covered] two cents.
I will often start with private auto properties, then refactor if necessary. I'll refactor to a property with a backing field, then replace the backing field with the "real" store, for instance Session or ViewState for an ASP.NET application.
From:
private int[] Property { get; set; }
to
private int[] _property;
private int[] Property
{
get { return _property; }
set { _property = value; }
}
to
private int[] _property;
private int[] Property
{
get
{
if (_property == null)
{
_property = new int[8];
}
return _property;
}
set { _property = value; }
}
to
private int[] Property
{
get
{
if (ViewState["PropertyKey"] == null)
{
ViewState["PropertyKey"] = new int[8];
}
return (int[]) ViewState["PropertyKey"];
}
set { ViewState["PropertyKey"] = value; }
}
Of course, I use ReSharper, so this takes less time to do than to post about.