Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# EF Core-在上一个操作完成之前在此上下文上启动的第二个操作。任何实例成员都不能保证是线程安全的_C#_Asp.net Core_Entity Framework Core_Ef Core 2.1 - Fatal编程技术网

C# EF Core-在上一个操作完成之前在此上下文上启动的第二个操作。任何实例成员都不能保证是线程安全的

C# EF Core-在上一个操作完成之前在此上下文上启动的第二个操作。任何实例成员都不能保证是线程安全的,c#,asp.net-core,entity-framework-core,ef-core-2.1,C#,Asp.net Core,Entity Framework Core,Ef Core 2.1,我正在使用EF Core 2.1,并试图通过使用任务(TPL)一次性更新多个实体: 公共异步任务更新趋势(IEnumerable事件) { 尝试 { var tasks=events.Select(异步实体=> { wait Task.Run(()=>Context.Entry(entity).Property(x=>x.attention.IsModified=true); wait Context.saveChangesSync(); }); 等待任务。何时(任务); } 捕获(例外情况除外

我正在使用
EF Core 2.1
,并试图通过使用
任务(TPL)一次性更新多个实体:

公共异步任务更新趋势(IEnumerable事件)
{
尝试
{
var tasks=events.Select(异步实体=>
{
wait Task.Run(()=>Context.Entry(entity).Property(x=>x.attention.IsModified=true);
wait Context.saveChangesSync();
});
等待任务。何时(任务);
}
捕获(例外情况除外)
{
抛出新异常(例如Message??ex.InnerException.Message);
}
}
但这是下面的错误

在上一个操作完成之前,在此上下文上启动了第二个操作。任何实例成员都不能保证线程安全

Startup.cs

services.AddScoped<IMyRepository, MyRepository>();
services.addScope();

如何解决这个问题?

你不能这么做。EF核心(和以前的EF 6一样)不是线程安全的

在开始下一项任务之前,您必须等待一项任务

var tasks = events.Select(async entity =>
{
    await Task.Run(() => Context.Entry(entity).Property(x => x.Attendance).IsModified = true);
    await Context.SaveChangesAsync();
});

await Task.WhenAll(tasks);
在这里,您将并行启动多个任务并等待它们。你得把它绕过去

foreach(var entity in events) 
{
    Context.Entry(entity).Property(x => x.Attendance).IsModified = true;
});
await Context.SaveChangesAsync();

它不确定为什么要逐个事件保存它(因此,该示例更改为在调用
savechangesync()
)之前执行所有修改的标志),因为它效率非常低。更合理的做法是更新所有属性,然后最后运行SaveChanges,因为保存更改时,EF Core将保存所有更改/跟踪的实体。当出现错误时,回滚也更容易(savechangesync中的操作发生在事务范围内)

您可以获得多个DbContext实例,有两种方法可以做到这一点

使用界面(推荐)

MyRepository
中:

private readonly IServiceScopeFactory serviceScopeFactory;
        public MyRepository(IServiceScopeFactory serviceScopeFactory)
        {
            this.serviceScopeFactory = serviceScopeFactory;
        }

        public async Task UpdateAttendance(IEnumerable<MyEvents> events)
        {
            try
            {
                var tasks = events.Select(async entity =>
                {
                    await Task.Run(() =>
                    {
                        using (var scope = serviceScopeFactory.CreateScope())
                        {
                            var context = scope.GetRequiredService<YourContextType>();
                            context.Entry(entity).Property(x => x.Attendance).IsModified = true;
                            await Context.SaveChangesAsync();
                        }
                    });
                });
                await Task.WhenAll(tasks);
            }
            catch (Exception ex)
            {
                //You really should not do this, did you have a look to ILogger?
                //If you only wants to stop when an exception gets thrown you can configure VS to do that, Debug menu -> Windows -> Exception Settings
                throw new Exception(ex.Message ?? ex.InnerException.Message);
            }
        }

您真的需要异步更改实体状态吗?这对我来说毫无意义。更改
已修改
不会持续太久!我想多次调用
SaveChanges
不是一个好主意。最好是更新所有实体并只调用一次。但是我没有得到任何错误,也没有在数据库中反映出值。您甚至对模型做了更改吗<代码>:IsModify
只会强制更新模型,但如果之前的值未更改,您只会看到更新后的数据。调试时,我添加了快速观察和检查Attendace的值,我看到了所需的值。为什么要手动设置它呢?实体是否处于分离状态(即通过WebApi调用)?通常EF Core在从数据库获取时会自动跟踪更改(并且跟踪未明确禁用)。对不起!我不明白你的意思。但这里添加了一些细节。在一个请求中,我获取Db实体,执行一些BL&Attention属性更新,然后需要保存它
private readonly IServiceScopeFactory serviceScopeFactory;
        public MyRepository(IServiceScopeFactory serviceScopeFactory)
        {
            this.serviceScopeFactory = serviceScopeFactory;
        }

        public async Task UpdateAttendance(IEnumerable<MyEvents> events)
        {
            try
            {
                var tasks = events.Select(async entity =>
                {
                    await Task.Run(() =>
                    {
                        using (var scope = serviceScopeFactory.CreateScope())
                        {
                            var context = scope.GetRequiredService<YourContextType>();
                            context.Entry(entity).Property(x => x.Attendance).IsModified = true;
                            await Context.SaveChangesAsync();
                        }
                    });
                });
                await Task.WhenAll(tasks);
            }
            catch (Exception ex)
            {
                //You really should not do this, did you have a look to ILogger?
                //If you only wants to stop when an exception gets thrown you can configure VS to do that, Debug menu -> Windows -> Exception Settings
                throw new Exception(ex.Message ?? ex.InnerException.Message);
            }
        }
services.AddDbContext<YourDbContext>(
    ServiceLifetime.Transient,
    options =>  options.UseSqlServer(Configuration.GetConnectionString("SomeConnectionStringName")));