【问题标题】:Dapper - Get information about the executed query statementDapper - 获取有关已执行查询语句的信息
【发布时间】:2020-08-17 05:17:26
【问题描述】:

我将 MySQL.Data 包替换为 Dapper。要从数据库中获取一个用户,我现在要做的就是

public Task<User> GetUser(string username) 
{
    using IDbConnection databaseConnection = new MySqlConnection("connectionString");
        
    DynamicParameters parameters = new DynamicParameters();
    parameters.Add("@username", username, DbType.String);
        
    return databaseConnection.QueryFirstOrDefaultAsync<User>(
        "SELECT * FROM person WHERE username = @username",
        parameters);
}

但我想添加一些跟踪级别的日志记录。有没有办法在执行之前获取查询字符串?

【问题讨论】:

  • 正如here MiniProfiler 解释的那样可能会有所帮助。这个问题是关于 Dapper-Extensions 的;但同样的事情也适用于 Dapper。
  • 或者,您也可以使用DbConnection 上的包装器来执行此操作,如here 所述。
  • @AmitJoshi 非常感谢你,但我不想为此使用外部工具,它只是访问生成的 sql 命令:)
  • 感谢您的第二条评论,但这对我来说感觉很不对劲。我必须重新实现/包装整个东西才能访问它......必须有一个更好的解决方案
  • Dapper 没有公开此功能,因为 Dapper 旨在尽可能简单和轻量。

标签: c# dapper


【解决方案1】:

创建您自己的 IDbCommand,它将包装您的真实 IDbCommand 并记录您想要拦截的内容。

但由于 Dapper 会自动创建 IDbCommand,因此您还必须创建自己的 IDbConnection(请参阅下面的 CreateCommand),它会包装您的真实 IDbConnection,以防万一使用您自己的 IDbCommand。

例子:

/// <summary>
/// This is just a wrapper around IDbConnection, 
/// which allows us to build a wrapped IDbCommand for logging/debugging
/// </summary>
public class InterceptedDbConnection : IDbConnection
{
    private readonly IDbConnection _conn;

    public InterceptedDbConnection(IDbConnection connection)
    {
        _conn = connection;
    }

    public string ConnectionString { get => _conn.ConnectionString; set => _conn.ConnectionString = value; }

    public int ConnectionTimeout => _conn.ConnectionTimeout;

    public string Database => _conn.Database;

    public ConnectionState State => _conn.State;

    public IDbTransaction BeginTransaction() => _conn.BeginTransaction();

    public IDbTransaction BeginTransaction(IsolationLevel il) => _conn.BeginTransaction(il);

    public void ChangeDatabase(string databaseName) => _conn.ChangeDatabase(databaseName);

    public void Close() => _conn.Close();

    public IDbCommand CreateCommand()
    {
        // Wrap real command under InterceptedDbCommand
        IDbCommand underlyingCommand = _conn.CreateCommand();
        return new InterceptedDbCommand(underlyingCommand);
        // you could also save this into a "LastCommand" to expose it 
        // and explore parameter types that Dapper used
    }

    public void Dispose() => _conn.Dispose();

    public void Open() => _conn.Open();
}

/// <summary>
/// This is just a wrapper around IDbCommand, 
/// which allows us to log queries
/// or inspect how Dapper is passing our Parameters
/// </summary>
public class InterceptedDbCommand : IDbCommand
{
    private readonly IDbCommand _cmd;
    public InterceptedDbCommand(IDbCommand command)
    {
        _cmd = command;
    }

    public string CommandText { get => _cmd.CommandText; set => _cmd.CommandText = value; }
    public int CommandTimeout { get => _cmd.CommandTimeout; set => _cmd.CommandTimeout = value; }
    public CommandType CommandType { get => _cmd.CommandType; set => _cmd.CommandType = value; }
    public IDbConnection Connection { get => _cmd.Connection; set => _cmd.Connection = value; }

    public IDataParameterCollection Parameters => _cmd.Parameters;

    public IDbTransaction Transaction { get => _cmd.Transaction; set => _cmd.Transaction = value; }
    public UpdateRowSource UpdatedRowSource { get => _cmd.UpdatedRowSource; set => _cmd.UpdatedRowSource = value; }

    public void Cancel() => _cmd.Cancel();

    public IDbDataParameter CreateParameter() => _cmd.CreateParameter();

    public void Dispose() => _cmd.Dispose();
    
    public void Prepare() => _cmd.Prepare();

    public int ExecuteNonQuery()
    {
        // TODO: Log _cmd.CommandText + _cmd.Parameters
        return _cmd.ExecuteNonQuery();
    }

    public IDataReader ExecuteReader()
    {
        // TODO: Log _cmd.CommandText + _cmd.Parameters
        return _cmd.ExecuteReader();
    }

    public IDataReader ExecuteReader(CommandBehavior behavior)
    {
        // TODO: Log _cmd.CommandText + _cmd.Parameters
        return _cmd.ExecuteReader(behavior);
    }

    public object ExecuteScalar()
    {
        // TODO: Log _cmd.CommandText + _cmd.Parameters
        return _cmd.ExecuteScalar();
    }

}

最后,只需将您的连接替换为已包装的连接:

IDbConnection databaseConnection = new InterceptedDbConnection(MySqlConnection("connectionString"));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多