How to detect collection changes in NHibernate

爱⌒轻易说出口 提交于 2020-02-25 05:47:50

问题


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:

  1. 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.

  2. the property name of the collection (I have classes with multiple collections)

  3. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!