.NetGurus

Diğer Yazılar

Google a Ekle

Add to Google



Logging Database Operations In NHibernate Environment

Bu makalenin Türkçe versiyonunu görmek için Tıklayınız.

Logging the database transactions is one of the important jobs of database application development. For security reasons you have to be able to determine who did what and when etc. There are numerous number of ways implementing the logging job according to the data access layer used. In this article I will try to accomplish this job for Nhibernate.

Nhibernate is an open source ORM tool which is the .Net port of the Hibernate that has been used in Java world for a long time. The basics of the ORM tools and NHibernate is not in the context of this article. The reader is supposed to have that knowledge.

NHibernate Session is responsible for the database transactions like inserting the newly added objects, updating the modified objects, deleting the removed objects etc. We are not interested in the underlying database management system and the SQL commands that are to be executed, we only interest in the objects we have in the application domain.

For example we have 2 classes in our application, Customer(Musteri) and City(Sehir).

The code that adds a new customer to our existing customers in database would be something as follows;

   Musteri musteri=new Musteri();   musteri.MusteriAdi = "";   musteri.Adresi = "";   musteri.BulunduguSehir=sehir;   nhSession.Save(musteri);  

Just calling the Save method of the Nhibernate Session will persist the new customer to the database.

During similiar database transactions the IInterceptor interface in NHibernate, makes it possible to access to the objects that is about to be persisted to the database. And at that point we have the object and know the type of transaction whether it is an insert, update, delete or etc. Now we should generate a class implementing the IInterceptor interface. Using this class we will intervene just before the point NHiberate completes the related database jobs and will get the properties of the object and log the transaction whereever we want.

IInterceptor interface has lots of usefull methods. These methods can be used for different purposes as well as the logging. Let's take a glance to the methods that is usefull in logging job:

OnLoad : Raises just before the objects are retrieved from database.
OnFlushDirty : Raises just before updating en existing object.
OnSave : Raises just before inserting a new object to the database.
OnDelete : Raises just before deleting an existing object from database. 

I think so much theoretical information is enough. Now let's see the IInterceptor interface in action.

First we should implement the IInterceptor interface in our new class LoggingInterceptor.

   public class LoggingInterceptor : IInterceptor  

By implementing the IInterceptor interface we should implement all the 14 methods of it in our LoggingInterceptor class. Now we should fill in the methods that we are going to use. For the remaining methods we return null and false for the ones having a return type of object and boolean respectively.  

For logging insert operations we use the OnSave method.

   public bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types){}  

OnSave method takes the following parameters;
entity: The object that is to be saved 
id : The primary key value of the object(entity)
state: The values of the properties of the object(entity)
propertyNames: The names of the properties of the object(entity)
types: The types of the properties of the object(entity)

We can get;

- the name of the type of the class(object) by calling entity.GetType().Name
- the values of each property of the object by looping through the propertyNames and  state object arrays
- the type of each property of the object by looping through the types object array.

Additionally for a web application;,
we can get;

- the IP address of the client by calling HttpContext.Current.Request.UserHostAddress 
- the name of the authenticated user by calling HttpContext.Current.User.Identity.Name

We should be carefull while getting the property values of the object. Because we can easily get the values if the property has a type of string, DateTime, integer or etc, but if the property has a complicated type such as Collection or another object(entity), the state[i].ToString() statement returns not the value but the type name of the property.

For example, during Saving a new customer example given above, if we try to get the property values as;

   for (int i = 0; i < propertyNames.Length; i++){       stringBuilder.Append(propertyNames[i]);       sb.Append(" : ");       sb.Append(currentState[i].ToString());   }  

we get the value of the BulunduguSehir property of the Musteri object as "Sehir" which is the name of the type of another object. However we need the values of the SehirAdi and SehirId properties of the BulunduguSehir property of the Musteri. To accomplish this job we should access the underlying object of the properties of the object and its properties with the help of Reflection and get the values of them by iterating through them.    

 

   for (int i = 0; i < propertyNames.Length; i++)  {       if (!types[i].IsAssociationType && !types[i].IsCollectionType && !types[i].IsComponentType && !types[i].IsEntityType && !types[i].IsMutable)       {            sb.Append(propertyNames[i]);            sb.Append(" : ");             if (state[i] != null)                 sb.Append(state[i].ToString());            else                 sb.Append("NULL");             sb.AppendLine();       }       else if (types[i].IsEntityType)       {           sb.Append(propertyNames[i]);           sb.Append(" : ");           if (state[i] != null)                sb.Append(types[i].Name);             sb.AppendLine();             PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(types[i].ReturnedClass);           for (int j = 0; j < pdc.Count; j++)           {                if (pdc[j].PropertyType.IsValueType || pdc[j].PropertyType==typeof(string))                {                     sb.Append(pdc[j].Name + " : " + pdc[j].GetValue(state[i]));                     sb.AppendLine();                }           }       }       else       {            sb.Append("NULL");            sb.AppendLine();       }  }  

After getting the information we need through the parameters of the OnSave method, now we can write the log to the Eventlog, File, Database or whereever we want.

For example if we want to log the changes to EventLog, the following code is enough.

   EventLog.WriteEntry("MusteriUygulamasi", sb.ToString());  


We generated the LoggingInterceptor class and got the information we need. Now how can we inform the NHibernate of our LoggingInterceptor class?

As I mentioned before, we know that all the database transactions is managed by NHibernate Session. And generally we open the NHibernate Session through the NHibernate SessionFactory as follows;

   NHibernate.ISessionFactory sessionFactory = new NHibernate.Cfg.Configuration().BuildSessionFactory();  NHibernate.ISession nhSession = sessionFactory.OpenSession();  


At this very point we can inform NHibernate Session of our LoggingInterceptor class and achieve the logging job as I described above. All we need is to change the code where we open the NHibernate Session as follows;

   NHibernate.ISessionFactory sessionFactory = new NHibernate.Cfg.Configuration().BuildSessionFactory();  NHibernate.ISession nhSession = sessionFactory.OpenSession(new LoggingInterceptor());  

At this article we saw the logging of the insertion of the new objects to the database. Similiarly we can log the update and delete operations. The attached project contains a sample application of how to use the LoggingInterceptor class. There I have used the OnFlushDirty and OnDelete methods nearby the OnSave method I have described here. 

LoggingWithNHibernate.zip (724,51 kb)


Categories: ASP.NET | ASP.NET | C# | C# | Database | Database
Posted by omer on 09 Mayıs 2008 Cuma 13:18
Permalink | Yorumlar (0) | Post RSSRSS comment feed

Yorumlar

Yorum ekle


(Gravatar simgesini gösterecek)

  Country flag

biuquote
  • Yorum
  • Canlı önizleme
Loading