实体框架核心:使用相同DbContext实例的不同线程

该应用程序是在ASP NET Core 3上开发的。为了记录用户操作,我决定在Project类中使用单个方法。面临从不同线程使用一个单例dbContext的问题。

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    string connection = Configuration.getconnectionString("ConnectionDB");
    services.AddDbContext<DataBaseContext>(options => options.UseSqlServer(connection),ServiceLifetime.Transient,ServiceLifetime.Singleton);

    services.AddSingleton<Project>();
}

Project.cs

public async Task AddUserLog(string action,string message,int userId)
{
    try
    {
        UserLog userLog = new UserLog()
        {
            action = action,Message = message,UserId = userId
            Datepoint = DateTime.Now
        };

        _dbContext.UserLog.Add(userLog);
        await _dbContext.SaveChangesAsync();
    }
    catch (Exception ex)
    {
        await AddSystemLog("Project","AddUserLog",ex.Message);
    }
}

SchemeController.cs

public class SchemeController : ControllerBase
{
    private readonly Project _project;

    public SchemeController(Project project)
    {
        _project = project;
    }

    [Authorize(Policy = "AdvancedControl")]
    [HttpPost("[action]")]
    public async Task SomeMethode()
    {
        for (int i = 0; i < 10; i++)
        {
            await _project.AddUserLog("Text","Message",42);
        }       
    }
}

已经在循环的第二次迭代中,我在AddUserLog方法中捕获了一个异常: “ 在上一个操作完成之前,第二个操作是在此上下文上开始的。这通常是由使用相同DbContext实例的不同线程引起的。”

我提出了几种解决方案:

  1. 将日志添加到缓冲区表,然后通过计时器将其保存到数据库。但这不是最好的出路;

  2. 将方法保存到数据库时对其进行阻止。

但是我不喜欢任何选择。

请告诉我解决此问题的正确方法。

WANGHUGANG 回答:实体框架核心:使用相同DbContext实例的不同线程

因此,当共享资源实现不是线程安全的(引发异常)时,您尝试使用共享资源(单个Project类)执行并行操作(保存UserLog)。

您至少可以通过三种方式解决此问题:

  1. 请勿使用共享资源:每个作用域(而不是单调)注册Project
  2. 不要并行执行操作:这很难实现,因为您制作的是webapp,并且不能强迫用户等待
  3. 将您的资源重构为线程安全的:在Project内添加锁/互斥锁/缓冲...

没有一种“正确”的方法-所有3种都是正确的。选择一个您喜欢的(或组合多个)。

推荐

通常使用作用域dbcontext(because connections are pooled),但是应该由应用的创建者来决定。

本文链接:https://www.f2er.com/3123988.html

大家都在问