A DotNet Raider

My adventures in the .NET world!
posts - 38, comments - 15, trackbacks - 0

My Links

News

Website View Martino Bordin's profile on LinkedIn XBOX 360 AVATAR - BORD1986
Locations of visitors to this page

Archives

Post Categories

Arch

BlogRoll

Codeplex

Google code

MSDN

Sites

Introduzione a Nhibernate.Envers (ovvero, come fare auditing in 3 righe di codice)

All’ultima UgiAltConf , tenutasi poco meno di un mese fa, Fabio Maulo ha presentato ConfORM e una libreria che in questi giorni è stata rilasciata in versione Alpha: Nhibernate.Envers.

Si tratta di un porting da Java che facilita le operazioni di auditing (per essere più precisi, stiamo parlando del Parallel Model definito da Martin Fowler).

In pratica, possiamo ottenere istanze delle nostre classi di dominio ad una specifica revisione/data (stile TFS), il tutto con poche righe di codice.

Interessante vero?

Vediamo come fare:

  1. Ho creato un’app console con 3 classi d’esempio: Customer e Product che ereditano da DomainObject.
    Domain                 
  2. Ho creato il mapping utilizzando FluentNH.
  3. Ho creato la configurazione di Envers, indicando quali sono le classi del nostro dominio per le quali vogliamo effettuare l’auditing (Customer e Product).
    1. // Create Envers Configuration
    2. var enversConfig = new NHibernate.Envers.Configuration.Fluent.FluentConfiguration();
    3. enversConfig.Audit(new[]
    4.     {
    5.         typeof(Customer),
    6.         typeof(Product)
    7.     });
  4. Ho passato la configurazione di Envers alla configurazione di Nhibernate, chiamando l’extension method IntegrateWithEnvers (riga 13).
    1. // Create configuration
    2. var config =
    3.     Fluently
    4.     .Configure()
    5.     .Database(MsSqlConfiguration
    6.                     .MsSql2008
    7.                     .ConnectionString(c => c.FromConnectionStringWithKey("db"))
    8.     .ProxyFactoryFactory<ProxyFactoryFactory>())
    9.     .Mappings(m => m
    10.                     .FluentMappings
    11.                     .AddFromAssemblyOf<Customer>())
    12.     .BuildConfiguration();
    13. config.IntegrateWithEnvers(enversConfig);
  5. Ho creato lo schema su un DB Sql2008.                                                                                                                   image

Noterete che oltre alle tabelle Customer e Product sono presenti 4 tabelle “particolari”:

  • REVINFO, contiene il numero progressivo e la data delle revisioni;
  • Customer_AUD, contiene le informazioni di auditing della tabella Customer, con riferimento alla tabella REVINFO;
  • Product_AUD, contiene le informazioni di auditing della tabella Product, con riferimento alla tabella REVINFO;
  • Customer_Product_AUD, contiene le informazioni di auditing per la relazione tra Customer e Auditing, con riferimento alla tabella REVINFO.

Ovviamente non ci sono Foreign Key tra le tabelle di Auditing e le tabelle target, perchè altrimenti non saremmo più in grado di eliminare record da quest’ultime.

Per interrogare le tabelle di Audit utilizzeremo un IAuditReader restituito da AuditReaderFactory.

  1. var auditeReader = AuditReaderFactory.Get(session);

Tra i metodi disponibili, ci sono:

  • Find, permette di recuperare lo stato di un oggetto data la sua chiave ed un numero di revisione;
  • GetRevisionDate, permette di recuperare la data di una revisione, passando l’id della stessa;
  • GetRevisionNumberForDate, permette di recuperare l’id di una revisione, passando la data della stessa
  • GetRevisions, ottiene l’elenco di tutte le revisione di un oggetto, data la sua chiave
  • CreateQuery, ritorna un oggetto AuditQueryCreator che è possibile utilizzare per ottenere le revisioni dei nostri oggetti in maniera rapida.

Nel mio test, ho creato un oggetto Customer con associati 3 Prodotti, ho modificato questi oggetti 2 volte (aggiungendo alle rispettive proprietà il carattere ‘a’), ho salvato le modifiche e poi eliminato gli oggetti.

Questo il risultato ottenuto:

image

Abbiamo quindi un numero di revisione condiviso tra le diverse tabelle (entità) che corrisponde ai commit della Unit Of Work (session), ottendendo di fatto un changeset.

In questo modo è possibile ricostruire un oggetto complesso ad un determinato stato, indipendentemente da quest’ultimo, in maniera molto semplice e senza modificare l’oggetto stesso!

Semplice, veloce, indolore Sorriso.

Ovviamente la libreria è ancora acerba, ma sono sicuro che verranno introdotti punti di estensibilità e customizzazione che attualmente non sembrano disponibili.

Altra nota dolente è la documentazione, al momento ho trovato solo quella relativa a Java su questo sito.

Per chi volesse a questo indirizzo è disponibile il mio esempio.

Potete invece scaricare Envers da qui ed ulteriori esempi qui.

Print | posted on mercoledì 9 marzo 2011 02:16 | Filed Under [ O/RM ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET