web-dev-qa-db-ja.com

非同期Dapperメソッドを使用したCancellationToken?

NugetのDapper1.31を使用しています。私はこの非常に単純なコードスニペットを持っています、

_string connString = "";
string query = "";
int val = 0;
CancellationTokenSource tokenSource = new CancellationTokenSource();
using (IDbConnection conn = new SqlConnection(connString))
{
    conn.Open();
    val = (await conn.QueryAsync<int>(query, tokenSource.Token)).FirstOrDefault();
}
_

押すと F12QueryAsyncで、それは私を指し示します

_public static Task<IEnumerable<T>> QueryAsync<T>
     (
        this IDbConnection cnn, 
        string sql, 
        dynamic param = null, 
        IDbTransaction transaction = null, 
        int? commandTimeout = null, 
        CommandType? commandType = null
     );
_

その署名にはCancellationTokenはありません。

質問:

  • スニペットが完全にビルド可能であるのはなぜですか仮定ソリューション全体にコンパイラエラーがないということですか?
  • 長時間実行されるSQLクエリを生成する方法がわからないため、tokenSource.Cancel()を呼び出すとメソッドが本当にキャンセルされるかどうかをテストできないことをお許しください。 .Cancel()は本当にメソッドをキャンセルしてOperationCancelledExceptionをスローしますか?

ありがとうございました!

27
Pedigree

キャンセルトークンをパラメータオブジェクトとして渡します。それはうまくいきません。

Dapperの最初の非同期メソッドはキャンセルトークンを公開しませんでした。それらをオプションのパラメーターとして(既存のアセンブリを壊さないように、別個のオーバーロードとして)追加しようとすると、 「あいまいなメソッド」のコンパイルの問題と非常に混同されました 。その結果、別のAPIを介してこれを公開する必要がありました。 CommandDefinitionと入力します。

val = (await conn.QueryAsync<int>(
    new CommandDefinition(query, cancellationToken: tokenSource.Token)
).FirstOrDefault();

次に、キャンセルトークンをチェーンのすべての予想される場所に渡します。実際に使用するのはADO.NETプロバイダーの仕事ですが、;ほとんどの場合は機能するようです。操作が進行中の場合は、SqlExceptionではなくOperationCancelledExceptionになる可能性があることに注意してください。これもADO.NETプロバイダーに依存しますが、非常に理にかなっています。重要な何かを中断した可能性があります。それは重大な接続の問題として表面化します。

質問について:

ソリューション全体にコンパイラエラーがないと仮定して、スニペットを完全にビルドできるのはなぜですか?

なぜなら...期待どおりに機能しない場合でも、有効なC#です。

長時間実行されるSQLクエリを生成する方法がわからないため、tokenSource.Cancel()を呼び出すと実際にメソッドがキャンセルされるかどうかをテストできないため、ご容赦ください。 .Cancel()は実際にメソッドをキャンセルし、OperationCancelledExceptionをスローしますか?

ADO.NETプロバイダー固有ですが、通常は機能します。 「長時間実行されるSQLクエリを生成する方法」の例として;ここでは、SQLサーバーのwaitfor delayコマンドがいくらか便利であり、統合テストで使用しています。

36
Marc Gravell

次の行を追加することで、 SqlMapper.cs in Dapper lib を修正できます。

    internal IDbCommand SetupCommand(IDbConnection cnn, Action<IDbCommand, object> paramReader)
    {
        var cmd = cnn.CreateCommand();

#if ASYNC
        // We will cancel our IDbCommand
        CancellationToken.Register(() => cmd.Cancel());
#endif

独自のDapperlibを再構築してお楽しみください:)

3
rislanov

SqlConnectionを使用してみて、キャンセル時に例外をキャッチしてください

var sqlConn = db.Database.Connection as SqlConnection;
sqlConn.Open();

_cmd = new SqlCommand(textCommand, sqlConn);
_cmd.ExecuteNonQuery();

SqlCommandをキャンセルします

_cmd.Cancel();
0
Matt

複数のスレッドに1つのSqlConnectionを使用していました。そして、各Threadが独自のSqlConnectionを作成するように変更すると、エラーは消えました。

0
Tadej