问题
How can I detect changes (additions and removals) from many to many sets and lists in NHibernate?
I'm using an interceptor to detect changes in the object model (for auditing and more), this works great for changes within object (using OnSave/OnFlushDirty) but not for collections.
When a collection changes the OnCollectionUpdate method is called but it only receives the key of the object holding the collection and the collection's latest items.
What I need is:
the object holding the collection (or at least type+key, the key is only unique within a class in my system) I only have the key now.
the property name of the collection (I have classes with multiple collections)
A list of added items and a list of removed items (or alternatively, the collection content before and after the current transaction).
Is there any way to get to this information?
回答1:
I am currently working on this myself. I haven't figured out your 3rd question myself yet (I am trying to find out though), but this should help you on your way with #1 and #2:
public static void SomeMethod(this ISession session, object entity)
{
//this will give you the information about your entity
String className = NHibernateProxyHelper.GuessClass(entity).FullName;
ISessionImplementor sessionImpl = session.GetSessionImplementation();
IEntityPersister persister = sessionImpl.Factory.GetEntityPersister(className);
//at this point you can use the persister object to retrieve the info you need:
//this gives you all properties and their values
Object[] currentState = persister.GetPropertyValues(entity, sessionImpl.EntityMode);
//this will return the types:
IType[] typeArray = persister.PropertyTypes;
//each IType object has a IsCollectionType bool which tells you if it is a collection:
bool isCollection = IType[0].IsCollectionType;
}
回答2:
If you does not override standart nhibernate collection (list, set, map), you always can get initial content of collection (content which was saved in base, before any changes). Example for lists:
PersistentList c = myCollection as PersistentList;
if ((c == null)||(!c.IsDirty)) {
return;
}
IEnumerable storedCollection = c.StoredSnapshot as IEnumerable;
if ((storedCollection == null)) {
return; //looks like a error
}
foreach(var element in storedCollection) {
//do something with old items
}
foreach(var element in storedCollection) {
//do something with new items
}
Certainly, you can figure out which elements have been added, deleted, or remain unchanged.
回答3:
Maybe is a little tricky, but what about creating a custom proxy ?
回答4:
This is not NHibernate code (it is Hibernate Java code), but googling the NHibernate API makes it look like similar code could get you started for NHibernate as well (there is a PersistentMap
class that has an Owner
property, and a CollectionSnapshot
property):
public void onCollectionUpdate(Object collection, Serializable id) {
System.out.println("****onCollectionUpdate");
if(collection instanceof PersistentMap) {
PersistentMap newValues = (PersistentMap) collection;
Object owner = newValues != null ? newValues.getOwner() : null;
Set<?> oldValues = newValues != null
? ((Map<?, ?>) newValues.getStoredSnapshot()).keySet()
: null;
System.out.println("owner: " + (owner != null ? owner.toString() : "(null)"));
System.out.println("oldValues: " + (oldValues != null ? oldValues.toString() : "(null)"));
System.out.println("newValues: " + (newValues != null ? newValues.toString() : "(null)"));
} else if (collection instanceof PersistentSet) {
PersistentSet newValues = (PersistentSet) collection;
Object owner = newValues != null ? newValues.getOwner() : null;
Set<?> oldValues = newValues != null
? ((Map<?, ?>) newValues.getStoredSnapshot()).keySet()
: null;
System.out.println("owner: " + (owner != null ? owner.toString() : "(null)"));
System.out.println("oldValues: " + (oldValues != null ? oldValues.toString() : "(null)"));
System.out.println("newValues: " + (newValues != null ? newValues.toString() : "(null)"));
}
}
Note that I know this isn't C# or NHibernate code. Please comment if this is totally unuseful for NHibernate (if the API isn't at all similar, even though my googling says it is similar) and I'll remove the post.
I'm immersed in Java land right now, or I'd try this out for you :)
来源:https://stackoverflow.com/questions/6522601/how-to-detect-collection-changes-in-nhibernate