Как войти / получить SQL-запрос, автоматически сгенерированный Dapper Extensions?

Я использую Dapper Extensions (DE) в качестве ORM. Он используется на уровне доступа к данным, который реализован с использованием шаблона репозитория. SQL Express - это внутренняя СУБД.

DE автоматически генерирует большинство запросов для меня. Я хочу регистрировать эти автоматически сгенерированные запросы для отладки.

Есть два способа добиться этого:

  1. Получите SQL-запрос, сгенерированный DE (до или после его выполнения) и запишите его в журнал. Это предпочтительный способ для меня, так как у меня уже есть свой модуль регистрации (использующий log4net) на месте. Единственное, что мне нужно, это SQL, сгенерированный DE.
  2. Интегрируйте DE с некоторыми инструментами регистрации. Я прочитал этот ответ. Это возможно с помощью инструмента MiniProfiler; но, как я уже сказал выше, у меня уже есть свой модуль регистрации. Я не хочу использовать другой инструмент только для регистрации запросов SQL.

Как войти / получить SQL-запрос, автоматически сгенерированный Dapper Extensions, без использования какого-либо другого инструмента ведения журнала?

Другой похожий вопрос - о Даппере. Этот вопрос о Dapper Extensions.

2 ответа

Решение

Глядя на комментарий от @MarcGravell и этот вопрос о том же с Dapper, MiniProfiler.Integrations лучший способ реализовать ведение журнала для Dapper Extensions.

Приведенный выше вопрос касается Даппера. Но Dapper Extensions использует Dapper внутренне. Таким образом, если ведение журнала реализовано для Dapper, то же самое работает и для Dapper Extensions.

Более подробную информацию можно найти на GitHub.

Пример кода, как показано ниже:

var factory = new SqlServerDbConnectionFactory(connectionString);
CustomDbProfiler cp = new CustomDbProfiler();
using(var connection = DbConnectionFactoryHelper.New(factory, cp))
{
    //DB Code
}
string log = cp.ProfilerContext.GetCommands();

Вы можете использовать в сборке CustomDbProfiler с помощью CustomDbProfiler.Current если это соответствует вашим потребностям. cp.ProfilerContext.GetCommands() вернет ВСЕ команды (успешные и неудачные) независимо от того, сколько раз вы вызываете метод. Я не уверен, но, возможно, поддержание сцепленной строки (StringBuilder может быть) внутренне. Если это так, это может замедлить производительность. Но в моем случае ведение журнала отключено по умолчанию. Я включаю ведение журнала только тогда, когда мне нужно что-то отладить. Так что это не проблема для меня.

Это также может вызвать проблему с объемом памяти, если одно соединение используется в очень большой области. Чтобы избежать этого, убедитесь, что CustomDbProfiler Экземпляр расположен правильно.

Как уже упоминалось в вопросе, изначально я хотел избежать этого (используя внешний инструмент / библиотеку). Но, MiniProfiler.Integrations НЕ пишет сам журнал. Я могу просто получить все сгенерированные запросы и предоставить их моему модулю логгера для выгрузки в файл. Вот почему это выглядит более подходящим для меня сейчас.


MiniProfiler.dll внутренне реализует аналогичную логику (в StackExchange.Profiling.Data.ProfiledDbConnection а также StackExchange.Profiling.Data.ProfiledDbCommand классы), который упоминается здесь и здесь. Так что, если я решу (в будущем возможно) обойти MiniProfiler, я сам смогу использовать эту реализацию.

Проект Dapper Extensions является открытым исходным кодом; все это знают. Я скачал его с GitHub и изменил в соответствии со своими потребностями.

Dapper Extensions строят / генерируют SQL-запрос внутри SqlGeneratorImpl учебный класс. В этом классе есть несколько методов, которые генерируют различные запросы.

Я добавил следующее свойство в DapperExtensions.DapperExtensionsstatic учебный класс:

static string lastGeneratedQuery;
public static string LastGeneratedQuery
{
    get
    {
        lock(_lock)
        {
            return lastGeneratedQuery;
        }
    }
    internal set
    {
        lock(_lock)
        {
            lastGeneratedQuery = value;
        }
    }
}

Кроме того, установите это свойство в различных методах SqlGeneratorImpl учебный класс. Ниже приведен пример, как я установил его в Select метод.

public virtual string Select(IClassMapper classMap, IPredicate predicate, IList<ISort> sort, IDictionary<string, object> parameters)
{
    ......
    ......

    StringBuilder sql = new StringBuilder(string.Format("SELECT {0} FROM {1}",
    ......
    ......

    DapperExtensions.LastGeneratedQuery = sql.ToString();

    return sql.ToString();
}

Базовые тесты работают хорошо; Я еще не проверил это полностью. Я буду обновлять этот ответ в случае каких-либо изменений.

Обратите внимание, что я не рекомендую это как стандартное решение; это просто взлом, который работает для моих нужд. Я действительно хотел бы видеть это как постоянную функцию в библиотеке. Пожалуйста, оставьте ответ, если у вас есть лучшее решение. В противном случае, пожалуйста, прокомментируйте, чтобы улучшить решение, предлагаемое здесь.

Другие вопросы по тегам