¿Cómo registrar / obtener una consulta SQL generada automáticamente por Dapper Extensions?

c# dapper dapper-extensions

Pregunta

Estoy usando Dapper Extensions (DE) como ORM. Se consume en la Capa de acceso a datos, que se implementa mediante el patrón Repository. SQL Express es RDBMS back-end.

DE genera automáticamente la mayoría de las consultas para mí. Quiero registrar esas consultas generadas automáticamente para propósitos de depuración.

Hay dos maneras en que puedo ver para lograr esto:

  1. Obtenga la consulta SQL generada por DE (antes o después de que se ejecute) y escríbala en el registro. Esta es la forma preferida para mí, ya que ya tengo mi módulo de registro (usando log4net). Lo único que necesito es el SQL generado por DE.
  2. Integrar DE con alguna herramienta de registro. Leí esta respuesta. Parece posible usando la herramienta MiniProfiler; pero como dije anteriormente, ya tengo mi módulo de registro en su lugar. No quiero usar otra herramienta solo para registrar consultas SQL.

¿Cómo registrar / obtener una consulta SQL generada automáticamente por Dapper Extensions sin usar ninguna otra herramienta de registro?

La otra pregunta similar es sobre Dapper. Esta pregunta es sobre Dapper Extensions.

Respuesta aceptada

Mirando el comentario de @MarcGravell y esta pregunta sobre hacer lo mismo con Dapper, MiniProfiler.Integrations es una mejor manera de implementar el registro para Dapper Extensions.

La pregunta relacionada es sobre Dapper. Pero Dapper Extensions usa Dapper internamente. Por lo tanto, si se implementa el registro para Dapper, también funciona para las extensiones Dapper.

Se pueden encontrar más detalles en GitHub .

El código de muestra es el siguiente:

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

Puede usar in-build CustomDbProfiler usando CustomDbProfiler.Current si es que lo necesita. cp.ProfilerContext.GetCommands() devolverá TODOS los comandos (éxito y cp.ProfilerContext.GetCommands() ) sin importar cuántas veces llame al método. No estoy seguro, pero podría estar manteniendo cadena concatenada ( StringBuilder puede ser) internamente. Si este es el caso, esto puede ralentizar el rendimiento. Pero, en mi caso, el registro está deshabilitado por defecto. Solo habilito el registro cuando necesito depurar algo. Entonces esto no es un problema para mí.

Esto también puede aumentar el problema de la huella de memoria si se usa una sola conexión en un alcance muy grande. Para evitar esto, asegúrese de que la instancia de CustomDbProfiler esté dispuesta correctamente.

Como se mencionó en la pregunta, inicialmente, quería evitar esto (usando una herramienta / biblioteca externa) . Pero, MiniProfiler.Integrations NO está escribiendo el registro en sí. Simplemente puedo obtener todas las consultas generadas y proporcionarlas a mi módulo logger para volcar en el archivo. Por eso, esto me parece más adecuado ahora.


MiniProfiler.dll implementa internamente una lógica similar (en las clases StackExchange.Profiling.Data.ProfiledDbConnection y StackExchange.Profiling.Data.ProfiledDbCommand ) que se menciona aquí y aquí . Por lo tanto, si decido (en el futuro podría) omitir MiniProfiler, puedo usar esta implementación yo mismo.


Respuesta popular

El proyecto Dapper Extensions es de código abierto; todos saben eso. Lo descargué de GitHub y lo modifiqué para satisfacer mis necesidades.

Dapper Extensions crea / genera consultas SQL internamente en la clase SqlGeneratorImpl . Hay varios métodos en esta clase que generan varias consultas.

DapperExtensions.DapperExtensions siguiente propiedad en static clase static DapperExtensions.DapperExtensions :

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

Además, establezca esta propiedad en varios métodos de la clase SqlGeneratorImpl . A continuación se muestra un ejemplo de cómo lo configuré en el método 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();
}

Las pruebas básicas funcionan bien; Todavía no lo he probado a fondo. Actualizaré esta respuesta en caso de cualquier cambio.

Tenga en cuenta que no recomiendo esto como solución estándar; esto es solo un truco que funciona para mis necesidades. Realmente me gustaría ver esto como una característica regular en la biblioteca. Por favor, publique una respuesta si tiene una mejor solución. De lo contrario, comenta para mejorar la solución sugerida aquí.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué