使用 Dapper 在数据库中执行动态实体

Execute Dynamic Entity in Database using Dapper

我的用户从客户端项目发送动态实体,所以我必须编写这样的方法

public Task<TUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
        throw new NotImplementedException();
        //string sql = "SELECT * FROM \"IdentityUsers\" WHERE \"NormalizedUserName\" = @NormalizedUserName;";
        //using (var connection =  _databaseConnectionFactory.CreateConnectionAsync())
        //{
        //   connection.QueryFirstOrDefaultAsync<TUser>(sql,
        //        new { NormalizedUserName = normalizedUserName });
        //}
    }

我的 IDatabaseConnectionFactory class 像下面那样绑定 ConnectionString:

public interface IDatabaseConnectionFactory
{       
    Task<IDbConnection> CreateConnectionAsync();
}

public class ConnectionFactory : IDatabaseConnectionFactory
{
    private readonly string _connectionString;

    public ConnectionFactory(string connectionString) => _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));

    public async Task<IDbConnection> CreateConnectionAsync()
    {
        try
        {
            var connString =  new NpgsqlConnection(_connectionString);
            await connString.OpenAsync();
            return connString;
        }
        catch
        {
            throw;
        }
    }
}

现在,我如何使用通用类型实体执行以下查询 TUser

  string sql = "SELECT * FROM \"IdentityUsers\" WHERE \"NormalizedUserName\" = @NormalizedUserName;";
    using (var connection =  _databaseConnectionFactory.CreateConnectionAsync())
    {
       connection.QueryFirstOrDefaultAsync<TUser>(sql,
            new { NormalizedUserName = normalizedUserName });
    }

注意:QueryFirstOrDefaultAsync 未在此处的连接下找到

您不是在等待 CreateConnectionAsync。不幸的是,在这种情况下并不明显,因为 Task<T> 是一次性的(所以 using 不会抱怨);试试看:

using (var connection = await _databaseConnectionFactory.CreateConnectionAsync())
{
    var user = await connection.QueryFirstOrDefaultAsync<TUser>(sql,
         new { NormalizedUserName = normalizedUserName });
}

提示:编译器输出(针对原始代码)有助于说明这一点:

Error CS1929 'Task<IDbConnection>' does not contain a definition for 'QueryFirstOrDefaultAsync' and the best extension method overload 'SqlMapper.QueryFirstOrDefaultAsync<TUser>(IDbConnection, string, object, IDbTransaction, int?, CommandType?)' requires a receiver of type 'IDbConnection'

这告诉我们:

  • 找到了一些QueryFirstOrDefaultAsync方法,但是不能用,因为
  • 目标表达式是 Task<IDbConnection>,而不是 IDbConnection

附带说明:值得一提的是,如果您只对连接执行一项操作,Dapper 可以为您处理打开和关闭连接——这有助于减少 async/await 操作。考虑一下,例如,如果您有一个 CreateClosedConnection() 方法 没有 打开连接,因此不需要异步;以下仍然有效:

using (var connection = _databaseConnectionFactory.CreateClosedConnection())
{
    var user = await connection.QueryFirstOrDefaultAsync<TUser>(sql,
         new { NormalizedUserName = normalizedUserName });
}

作为 QueryFirstOrDefaultAsync 的一部分,Dapper 会为您处理 await OpenAsync()