Here is (roughly sketched) what I did:
Create a custom implementation of the IDbCommand
interface, which internally delegates all to the real work to SqlCommand
(assume it is called LoggingDbCommand
for the purpose of discussion).
Create a derived class of the NHibernate class SqlClientDriver
. It should look something like this:
public class LoggingSqlClientDriver : SqlClientDriver
{
public override IDbCommand CreateCommand()
{
return new LoggingDbCommand(base.CreateCommand());
}
}
Register your Client Driver in the NHibernate Configuration (see NHibernate docs for details).
Mind you, I did all this for NHibernate 1.1.2 so there might be some changes required for newer versions. But I guess the idea itself will still be working.
OK, the real meat will be in your implementation of LoggingDbCommand
. I will only draft you some example method implementations, but I guess you'll get the picture and can do likewise for the other Execute*() methods.:
public int ExecuteNonQuery()
{
try
{
// m_command holds the inner, true, SqlCommand object.
return m_command.ExecuteNonQuery();
}
catch
{
LogCommand();
throw; // pass exception on!
}
}
The guts are, of course, in the LogCommand() method, in which you have "full access" to all the details of the executed command:
- The command text (with the parameter placeholders in it like specified) through
m_command.CommandText
- The parameters and their values through to the
m_command.Parameters
collection
What is left to do (I've done it but can't post due to contracts - lame but true, sorry) is to assemble that information into a proper SQL-string (hint: don't bother replacing the parameters in the command text, just list them underneath like NHibernate's own logger does).
Sidebar: You might want to refrain from even attempting to log if the the exception is something considered fatal (AccessViolationException, OOM, etc.) to make sure you don't make things worse by trying to log in the face of something already pretty catastrophic.
Example:
try
{
// ... same as above ...
}
catch (Exception ex)
{
if (!(ex is OutOfMemoryException || ex is AccessViolationException || /* others */)
LogCommand();
throw; // rethrow! original exception.
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…