web-dev-qa-db-ja.com

Dapper QueryAsyncを使用して単一のオブジェクトを返す

残念ながら私たちのDBは90年代にさかのぼります。そのレガシーは非常に強力であるため、CRUD操作のほとんどを実行するためにSPを使用しています。しかし、Dapperはかなり適しているようで、試してみたところです。

ただし、1つのデータ行を処理する方法については少し心配です。この場合、QueryAsyncを使用してSP IDを渡します。ご覧のとおり、オブジェクトは非同期呼び出し(*)。

困るのかな?もしそうなら、誰もそれを処理する方法を知っていますか?代わりに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オブジェクトは非同期メソッドではありません。

11

まず、null checkは必要ないと思います。Dapperはクエリに対して0行を返します。これは[〜#〜] true [〜#〜] for SQL Serverbutであることに注意してください。他のRDBMSでも同じです。したがって、この

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

単に次のように書くことができます

return schemePolicy.FirstOrDefault();

本当の懸念に取り組むために、あなたは言及しました:

オブジェクトが非同期呼び出しの外に戻っている(*)

それは真実ではありません。どちらかの方法で記述した場合、[〜#〜] only [〜#〜]クエリの実行後にオブジェクトを取得します。したがって、次の2つのコードセットは同じ動作をします。

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)であることを確認する方法にありますターゲットオブジェクトは、クエリの実行が終了したときにのみ取得されます。以下は、テストできるコンソールアプリのスニペットです。

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();
}
11
von v.

Dapperは QueryFirstOrDefaultAsync() をサポートしているため、次のようなコードを記述できます。

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