2009-03-09 10 views
9

Je suis en train de revoir et de réimplémenter le code qui m'a amené à demander this question à propos de l'audit des données dans NHibernate. Mais cette fois, je veux aller avec l » suggestionSean Carpenter et mettre en œuvre le ISaveOrUpdateEventListener (nouveau dans NHibernate 2.x)Audit des données dans NHibernate en utilisant les événements

Je veux ajouter une ligne dans une base de données pour chaque changement de chaque propriété avec la valeur ancienne et la nouvelle plus tard dans l'interface utilisateur que je peux dire des choses comme « utilisateur Bob a changé la propriété de A à B le 9 Mars de 2009 de Wibble à 21h04 »

Quelle est la meilleure façon de comparer l'état de l'objet à travailler sur lequel des les propriétés de l'objet ont changé?

Vous pouvez obtenir l'état chargé de l'objet par ce qui suit:

public void OnSaveOrUpdate(SaveOrUpdateEvent saveOrUpdateEvent) 
    { 
     object[] foo = saveOrUpdateEvent.Entry.LoadedState; 
    } 

Et je suppose que je pourrais utiliser la réflexion pour travailler sur les propriétés ont changé, mais j'ai creuser autour et il n » Il semble que ce soit un ensemble de propriétés à comparer. J'aurais pensé qu'il y aurait une méthode GetChangedProperties() ou quelque chose.

je pouvais toujours obtenir l'ancien objet de la base de données telle qu'elle est et comparer, mais qui est encore une autre base de données et frappé semblerait la main lourde dans ce scénario.

Quelle est la meilleure direction à prendre avec cela?

P.S. Au cas où cela ferait une différence, il s'agit d'un projet d'architecture ASP.NET-MVC/S # arp.

Répondre

6

Je ne sais pas comment obtenir ce que vous voulez avec l'interface ISaveOrUpdateListener - vous pouvez toutefois profiter du fait que IPreUpdateEventListener et IPreInsertEventListener interfaces les deux fournissent ce dont vous avez besoin ... par exemple faire quelque chose comme ceci:

public bool OnPreUpdate(PreUpdateEvent evt) 
{ 
    string[] names = evt.Persister.PropertyNames; 
    for(int index = 0; index < names.Length; index++) 
    { 
     // compare evt.State[index] to evt.OldState[index] and get 
     // the name of the changed property from 'names' 
     // (...) 
    } 
} 

et faites la même chose pour le pré-insertion.

+0

Cela a fonctionné pour moi. Merci mookid. –

+0

Merci pour le "et obtenir le nom de la propriété modifiée de 'noms'". J'étais sur le net pendant 15 minutes à la recherche d'un moyen fiable de faire correspondre l'objet aux valeurs. – SamuelKDavis

0

Vous pouvez implémenter un motif Memento pour sérialiser l'état à partir de la charge initiale, via ILoadEventListener. Évidemment, vous ne voulez pas stocker des collections/relations ou vous dupliquer tout le graphe d'objet. Vous pouvez ensuite tirer cela et comparer dans votre ISaveOrUpdateEventListener.

11

Vous pouvez également utiliser la méthode FindDirty sur le Persister à laisser faire les comparaisons NHibernate pour vous:

var dirtyFieldIndexes = @event.Persister.FindDirty(@event.State, @event.OldState, @event.Entity, @event.Session); 

foreach (var dirtyFieldIndex in dirtyFieldIndexes) 
{ 
    var oldValue = @event.OldState[dirtyFieldIndex]; 
    var newValue = @event.State[dirtyFieldIndex]; 

    // Log values to new "AuditLog" object and save appropriately. 
} 
+0

toutes sortes de génial! –

Questions connexes