获取连接在forEach

时间:2017-09-11 19:53:43

标签: c# sql-server foreach dapper 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每次更新,所以为什么我会收到此错误。

注意:我无法控制连接字符串,因此无法启用MARS。

3 个答案:

答案 0 :(得分:26)

您需要在连接字符串中添加属性MultipleActiveResultSets并将其设置为true以允许多个活动结果集。

 "Data Source=MSSQL1;" & _  
    "Initial Catalog=AdventureWorks;Integrated Security=SSPI;" & _  
    "MultipleActiveResultSets=True"  

阅读详情:https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/enabling-multiple-active-result-sets

答案 1 :(得分:6)

该代码为列表中的每个项启动一个Task,但不等待每个任务在开始下一个任务之前完成。在每个任务中,它等待更新完成。尝试

 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(),而不是等待每项任务。 EG

    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
    }

答案 2 :(得分:2)

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,如下:

await Task.WhenAll(source.Select(transform)); // not MARS-safe
await source.WhenAllOneByOne(transform); // MARS-safe