J'ai le code suivant:
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));
Je reçois le
InvalidOperationException: la connexion ne prend pas en charge MultipleActiveResultSets
Je ne comprends pas que je suis await
dans chaque mise à jour, alors pourquoi cette erreur est-elle générée?.
Remarque: je n'ai aucun contrôle sur la chaîne de connexion, je ne peux donc pas activer MARS.
Ce code lance une tâche pour chaque élément de la liste, mais n'attend pas la fin de chaque tâche avant de commencer le suivant. Dans chaque tâche, il attend la fin de la mise à jour. Essayer
Enumerable.Range(1, 10).ToList().ForEach(async i => await Task.Delay(1000).ContinueWith(t => Console.WriteLine(DateTime.Now)));
Qui est équivalent à
foreach (var i in Enumerable.Range(1, 10).ToList() )
{
var task = Task.Delay(1000).ContinueWith(t => Console.WriteLine(DateTime.Now));
}
Si vous utilisez une méthode non asynchrone, vous devrez attendre (), pas attendre chaque tâche. PAR EXEMPLE
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
}
Vous devez ajouter l'attribut MultipleActiveResultSets
dans la chaîne de connexion et le définir sur true pour autoriser plusieurs ensembles de résultats actifs.
"Data Source=MSSQL1;" & _
"Initial Catalog=AdventureWorks;Integrated Security=SSPI;" & _
"MultipleActiveResultSets=True"
Pour en savoir plus, consultez: https://docs.Microsoft.com/en-us/dotnet/framework/data/adonet/sql/enabling-multiple-active-result-sets
MARS a quelques limitations et également une surcharge non nulle. Vous pouvez utiliser les aides suivantes pour rendre les mises à jour séquentielles:
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
}
Donc, votre exemple se transformerait en
await test.WhenAllOneByOne(conn.UpdateAsync);
J'appelle généralement le deuxième assistant au lieu de Task.WhenAll
, comme suit:
await Task.WhenAll(source.Select(transform)); // not MARS-safe
await source.WhenAllOneByOne(transform); // MARS-safe