【问题标题】:Using Dapper QueryAsync to return a single object使用 Dapper QueryAsync 返回单个对象
【发布时间】:2015-07-06 09:27:49
【问题描述】:

不幸的是,我们的数据库可以追溯到 90 年代。它的遗产是如此强大,以至于我们仍在使用 SP 来完成大部分 CRUD 操作。但是,Dapper 似乎很适合,我们才刚刚开始使用它。

但是,我有点担心如何处理单个数据行。在这种情况下,我使用 QueryAsync 调用传递 ID 的 SP。如您所见,对象在异步调用之外返回(*)。

我会遇到麻烦吗?如果是这样,有人知道如何处理吗?我需要改用 QuerySync 吗?

public class SchemePolicyRepository : ISchemePolicyRepository
{
    private readonly SqlConnection sql;

    protected SchemePolicyRepository(SqlConnection connection)
    {
        sql = connection;
    }
    ... 
    public async Task<SchemePolicy> GetById(string id)
    {
        var schemePolicy = await sql.QueryAsync<SchemePolicy>("risk.iE_GetSchemePolicyById",
            new { Id = id },
            commandType: CommandType.StoredProcedure);
        return schemePolicy != null ? schemePolicy.FirstOrDefault() : null;
    }
    ...
}

(*)FirstOfDefault() 返回的 SchemePolicy 对象不是异步方法。

【问题讨论】:

  • 如您所见,对象没有从异步调用中返回。 这是什么意思?你的意思是你的查询不起作用?
  • 存储过程没什么问题,它们是 SQL,就像生成的沉重、缓慢的 ORM 一样。
  • 感谢@YuvalItzchakov,我已经更新了帖子
  • @Crowcoder 你是对的,这就是为什么我们更喜欢使用 Dapper 而不是 EF。旧式 ADO.NET 仍然是我们喜欢在这里使用的东西 :)
  • 所以基本上,你很担心,因为FirstOrDefault 不是异步的?

标签: c# asynchronous repository dapper


【解决方案1】:

首先,我认为您不需要null check,Dapper 将返回零行进行查询。请注意,对于SQL Server,这是TRUE对于任何其他RDBMS 应该是相同的。所以这个

return schemePolicy != null ? schemePolicy.FirstOrDefault() : null;

可以写成

return schemePolicy.FirstOrDefault();

现在要解决真正的问题,您提到:

对象在异步调用之外返回(*)

那不是真的。如果您以任何一种方式编写它,您将在查询运行后获取您的对象。所以下面的两组代码会产生相同的行为:

var schemePolicy = await sql.QueryAsync<SchemePolicy>("sp", {rest of code});
return schemePolicy.FirstOrDefault();

var schemePolicy = sql.QueryAsync<SchemePolicy>("sp", {rest of code});
return schemePolicy.Result.FirstOrDefault();

现在真正关心的是您调用 GetById 的方式,以确保 (1) 该方法不会阻塞任何其他线程并且 (2)只有当查询完成运行时,您才会获得您的目标对象。这是一个控制台应用程序的 sn-p,您可以使用它进行测试:

static async void GetValue()
{
    var repo = new SchemePolicyRepository(new DbManager()); // creates an open connection 
    var result = await repo.GetById();
    Console.WriteLine(result);
}

static void Main(string[] args)
{
    GetValue();   
    Console.WriteLine("Query is running...");
    Console.ReadKey();
}

该测试将显示 GetValue 因此调用 GetById 方法不会阻塞其余代码。此外,在处理查询之前,FirstOrDefault 不会返回任何内容。

这是查询的支持代码,以防有人想尝试验证该概念是否有效(代码适用于 SQL Server 2008 及更高版本):

public async Task<int> GetById()
{
    var sql = @"
WAITFOR DELAY '00:00:05';
select 1 where 1=1";

    var result = await {the_open_connection}.QueryAsync<int>(sql);    
    return result.FirstOrDefault();
}

【讨论】:

    【解决方案2】:

    Dapper 现在支持QueryFirstOrDefaultAsync(),所以你可以这样写代码,

    public async Task<SchemePolicy> GetById(string id)
    {
        return await sql.QueryFirstOrDefaultAsync<SchemePolicy>("risk.iE_GetSchemePolicyById",
            new { Id = id },
            commandType: CommandType.StoredProcedure);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-07
      • 2013-09-13
      • 1970-01-01
      相关资源
      最近更新 更多