Ответ 1
Вот (грубо набросок), что я сделал:
-
Создайте пользовательскую реализацию интерфейса
IDbCommand
, который внутренне делегирует всех к реальной работеSqlCommand
(предположим, что она называетсяLoggingDbCommand
для обсуждения). -
Создайте производный класс класса NHibernate
SqlClientDriver
. Он должен выглядеть примерно так:public class LoggingSqlClientDriver : SqlClientDriver { public override IDbCommand CreateCommand() { return new LoggingDbCommand(base.CreateCommand()); } }
-
Зарегистрируйте свой драйвер клиента в конфигурации NHibernate (подробности см. в документах NHibernate).
Имейте в виду, я сделал все это для NHibernate 1.1.2, поэтому для более новых версий могут потребоваться некоторые изменения. Но я думаю, что сама идея все равно будет работать.
Хорошо, реальное мясо будет в вашей реализации LoggingDbCommand
. Я только вычеркнул бы вам некоторые примеры реализации методов, но я думаю, вы получите изображение и можете сделать то же самое для других методов Execute *().:
public int ExecuteNonQuery()
{
try
{
// m_command holds the inner, true, SqlCommand object.
return m_command.ExecuteNonQuery();
}
catch
{
LogCommand();
throw; // pass exception on!
}
}
Разумеется, кишки относятся к методу LogCommand(), в котором у вас есть "полный доступ" ко всем деталям выполненной команды:
- Текст команды (с указанными в ней записями параметров, как указано) через
m_command.CommandText
- Параметры и их значения до коллекции
m_command.Parameters
Что нужно сделать (я сделал это, но не могу выполнить запись из-за контрактов - хромой, но правда, извините) заключается в том, чтобы собрать эту информацию в правильную строку SQL (подсказка: не беспокойтесь о замене параметров в тексте команды, просто перечислите их под ним, как это делает собственный регистратор NHibernate).
Боковая панель:. Возможно, вы захотите воздержаться от попыток записи, если исключение является чем-то признанным фатальным (AccessViolationException, OOM и т.д.), чтобы убедиться, что вы не делаете хуже, пытаясь чтобы войти в лицо чего-то уже довольно катастрофического.
Пример:
try
{
// ... same as above ...
}
catch (Exception ex)
{
if (!(ex is OutOfMemoryException || ex is AccessViolationException || /* others */)
LogCommand();
throw; // rethrow! original exception.
}