如何在DBContext上同时执行多个操作?

发布于 2025-02-06 18:35:12 字数 1652 浏览 1 评论 0原文

我有以下背景服务运行:

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await Task.Run(async () =>
            {
                while (!stoppingToken.IsCancellationRequested)
                {
                    using (var scope = _scopeFactory.CreateScope())
                    {
                        DataContext dbContext = scope.ServiceProvider.GetRequiredService<DataContext>();
                        var tasks = new List<Task>();
                        tasks.Add(siteA.ProcessSchedule(SportLeagues.MLB, logger, dbContext));
                        tasks.Add(siteB.ProcessSchedule(SportLeagues.MLB, logger, dbContext));
                        //....more of same task
                        await Task.WhenAll(tasks);
                        await dbContext.SaveChangesAsync();
                        await Task.Delay(0, stoppingToken);
                    }
                }
            });
        }

我不断获得此错误

System.InvalidOperationException: 
    A second operation was started on this context instance before a previous operation completed.

,我可以为每个任务进行重构并创建一个dbContext,但是如果可能的话,我更喜欢使用单个dbcontext。

我还尝试将我的dbcontext添加为瞬态:

builder.Services.AddDbContext<DataContext>(options =>
{
    options.UseInMemoryDatabase("db");
}, ServiceLifetime.Transient);

但这无济于事。我是否以不正确的方式创建了我的dbcontext?还是为每个任务创建新的dbContext的最佳方法?对于更多上下文,这是一个不断运行的背景任务,需要一秒钟才能完成,并且将拥有大约20个任务。每秒创建和破坏20 dbContext,以及必须执行20 dbContext Saves,听起来很低。

I have the following background service running:

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await Task.Run(async () =>
            {
                while (!stoppingToken.IsCancellationRequested)
                {
                    using (var scope = _scopeFactory.CreateScope())
                    {
                        DataContext dbContext = scope.ServiceProvider.GetRequiredService<DataContext>();
                        var tasks = new List<Task>();
                        tasks.Add(siteA.ProcessSchedule(SportLeagues.MLB, logger, dbContext));
                        tasks.Add(siteB.ProcessSchedule(SportLeagues.MLB, logger, dbContext));
                        //....more of same task
                        await Task.WhenAll(tasks);
                        await dbContext.SaveChangesAsync();
                        await Task.Delay(0, stoppingToken);
                    }
                }
            });
        }

I constantly get this error

System.InvalidOperationException: 
    A second operation was started on this context instance before a previous operation completed.

I can refactor and create a dbContext for each task, however I would prefer to use a single dbContext if possible.

I also tried adding my dbContext as transient:

builder.Services.AddDbContext<DataContext>(options =>
{
    options.UseInMemoryDatabase("db");
}, ServiceLifetime.Transient);

But this did not help. Am I creating my dbContext in an incorrect way? Or is the best approach to create a new dbContext for each task? For more context, this is a constantly running background task, it takes a second to complete and it will have around 20 tasks. It sounds pretty inefficient to be creating and destroying 20 dbContext every second, along with having to do 20 dbContext saves.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

抱着落日 2025-02-13 18:35:12

您的设计有一些问题。一方面,dbContext不是线程安全,因此不能安全地从多个任务或线程中使用。

dbContext也在跟踪对象(除非asnotracking(),并且在所有查询操作中使用类似的方法)。如果您在很长一段时间内一直使用相同的dbContext实例,那么它将需要大量内存,并且其性能也可能会降低。

另一方面,实例化新的dbContext应该是一个便宜的操作,除非它通过包含太多表格会肿,但这将是另一种设计缺陷。

所有这些考虑都指向实例化新的dbContext的方向,而不是重复使用实例。如果后续操作需要传达状态,则重复使用dbContext是该目的不太有利的解决方案之一。

There are a couple of issues with your design. For one thing, DbContext is not thread-safe, and hence cannot be used from multiple tasks or threads safely.

DbContext is also tracking objects (unless AsNoTracking() and similar methods are used on all query operations). If you keep using the same DbContext instance for a long period of time, then it will take a lot of memory, and its performance might reduce as well.

On the other hand, instantiating a new DbContext should be a cheap operation, unless it is bloated by containing too many tables - that would be a design flaw of a different kind.

All these considerations point into direction of instantiating a new DbContext in every operation that needs it, rather than reusing instances. If subsequent operations need to communicate state, then reusing a DbContext is one of the less favorable solutions to that end.

回首观望 2025-02-13 18:35:12

激活连接字符串中的火星应解决您的问题。

类似:“数据源= MSSQL1;初始目录= AdventureWorks; Integrated Security = Sspi; 多重反应viversultsetsetsetsetsetsetsets = true

读取此Microsoft文档以获取更多信息:

https://lealen.microsoft.com/en-en-us/dotnet/framework /DATA/ADONET/SQL/启用 - 激活-Result-Sets

Activating MARS in your Connection String should solve your problem.

like: "Data Source=MSSQL1;Initial Catalog=AdventureWorks;Integrated Security=SSPI;MultipleActiveResultSets=True"

Read This Microsoft Document For More Info:

https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql/enabling-multiple-active-result-sets

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文