Dapper.SimpleCRUDを使用した次のコードがあります。
var test = new FallEnvironmentalCondition[] {
new FallEnvironmentalCondition {Id=40,FallId=3,EnvironmentalConditionId=1},
new FallEnvironmentalCondition {Id=41,FallId=3,EnvironmentalConditionId=2},
new FallEnvironmentalCondition {Id=42,FallId=3,EnvironmentalConditionId=3}
};
test.ToList().ForEach(async x => await conn.UpdateAsync(x));
このコードを使用すると、次の例外が発生します。
InvalidOperationException:接続はMultipleActiveResultSetsをサポートしていません
私は各更新をawait
ingしていることを理解していないので、なぜこのエラーが発生するのですか?.
注:接続文字列を制御できないため、MARSをオンにできません。
このコードは、リスト内の各項目のタスクを開始しますが、次のタスクを開始する前に、各タスクが完了するのを待機しません。各タスク内では、更新が完了するのを待ちます。試す
Enumerable.Range(1, 10).ToList().ForEach(async i => await Task.Delay(1000).ContinueWith(t => Console.WriteLine(DateTime.Now)));
これは
foreach (var i in Enumerable.Range(1, 10).ToList() )
{
var task = Task.Delay(1000).ContinueWith(t => Console.WriteLine(DateTime.Now));
}
非非同期メソッドを使用している場合は、各タスクを待つのではなく、Wait()を実行する必要があります。例えば
foreach (var i in Enumerable.Range(1, 10).ToList() )
{
var task = Task.Delay(1000).ContinueWith(t => Console.WriteLine(DateTime.Now));
//possibly do other stuff on this thread
task.Wait(); //wait for this task to complete
}
複数のアクティブな結果セットを許可するには、接続文字列に属性MultipleActiveResultSets
を追加してtrueに設定する必要があります。
"Data Source=MSSQL1;" & _
"Initial Catalog=AdventureWorks;Integrated Security=SSPI;" & _
"MultipleActiveResultSets=True"
問題はForEachメソッドでない非同期メソッドです。 はできませんラムダが返すタスクを待ちます。そのコードを実行すると、すべてのタスクが実行され、それらのいずれかの完了を待ちません。
一般的なポイント:ラムダを非同期としてマークしても、それに渡す同期メソッドが非同期で動作することにはなりません。
解決策:タスクの完了を待つforeachループを使用する必要があります。
例:foreach(var x in xs)await f(x);
必要に応じて、ヘルパーメソッドでラップできます。
(私はそれが古い質問であることを知っていますが、明確に答えられたとは思いません)
MARSにはいくつかの制限があり、オーバーヘッドもゼロではありません。次のヘルパーを使用して、更新を順次実行できます。
public static async Task WhenAllOneByOne<T>(this IEnumerable<T> source, Func<T, Task> process)
{
foreach (var item in source)
await process(item);
}
public static async Task<List<U>> WhenAllOneByOne<T, U>(this IEnumerable<T> source, Func<T, Task<U>> transform)
{
var results = new List<U>();
foreach (var item in source)
results.Add(await transform(item));
return results;
// I would use yield return but unfortunately it is not supported in async methods
}
だからあなたの例は
await test.WhenAllOneByOne(conn.UpdateAsync);
私は通常、次のようにTask.WhenAll
ではなく2番目のヘルパーを呼び出します。
await Task.WhenAll(source.Select(transform)); // not MARS-safe
await source.WhenAllOneByOne(transform); // MARS-safe