在控制器中创建EF Core DBContext以进行多线程处理?

时间:2017-05-04 16:30:57

标签: c# entity-framework-core

在我的一个控制器中,我有一个异步方法,必须同时进行几个db调用,所以我这样设置:

+---------+----------+------------+------+
| item_id | order_id | product_id | qty  |
+---------+----------+------------+------+
|   15329 |     7369 |      18253 |    3 | // 3
|   15330 |     7370 |      18253 |    1 | // 4
|   15331 |     7371 |      18253 |    7 | // 11
|   15332 |     7372 |      18253 |    1 | // 12
|   15333 |     7373 |      18253 |    1 | // 13
+---------+----------+------------+------+

我存储了注入的上下文。在特定方法中:

public xxxController(IConfiguration configuration, xxxContext xxxContext, xxx2Context xxx2Context)
   : base(xxxContext)

在WhenAll内部,我需要为每个项使用xxxContext,因此我得到了非线程安全异常。

创建新DbContext的正确方法是什么?现在我正在做:

var v = await Task.WhenAll(... )

所以我从注入的现有上下文中获取连接字符串,并使用它来创建一个新的连接字符串。

连接字符串存储在appSettings.json中。在" ConnectionStrings"部分。

是否有更简洁的方法来创建多线程的上下文?

2 个答案:

答案 0 :(得分:0)

为此,我创建了类似工厂类的东西,它可以为每次调用提供上下文。对于你的情况,它可以是

public class AppDependencyResolver
{
    private static AppDependencyResolver _resolver;

    public static AppDependencyResolver Current
    {
        get
        {
            if (_resolver == null)
                throw new Exception("AppDependencyResolver not initialized. You should initialize it in Startup class");
            return _resolver;
        }
    }

    public static void Init(IServiceProvider services)
    {
        _resolver = new AppDependencyResolver(services);
    }

    private readonly IServiceProvider _serviceProvider;

    private AppDependencyResolver(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public xxxContext CreatexxxContextinCurrentThread()
    {
        var scopeResolver = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
        return scopeResolver.ServiceProvider.GetRequiredService<xxxContext>();
    }
}

比你应该在Startup中调用Init方法

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    AppDependencyResolver.Init(app.ApplicationServices);
    //other configure code
}

您可以在github

上查看我的方法

答案 1 :(得分:-1)

我害怕以这种方式执行异步方法

var task = Task.Run(() => MyAsynchronosMethod());

DbContext操作是输入输出操作,您不需要在不同的线程上执行它们同时工作&#34;。你可以在没有新线程的情况下使它工作。

public MyController(IConfiguration configuration, AContext aContext, BContext bContext)
    : base(aContext)
{ 
    _aContext = aContext;
    _bContext = bContext;
}

public Task<IActionResult> GetSomething(int id)
{
    var customerTask = aContext.Customers
                                     .FirstOrDefaultAsync(customer => customer.Id == id);
    var sellerTask = aContext.Sellers
                                   .FirstOrDefaultAsync(seller => seller.CustomerId == id);
    var ordersTask = bContext.Orders
                                   .Where(order => order.CustomerId == id)
                                   .ToListAsync();
    var invoicesTask = bContext.Invoices
                                     .Where(invoice => invoice.CustomerId == id)
                                     .ToListAsync();
    var allTasks = new[] { customerTask, sellerTask, ordersTask, invoicesTask};
    await Task.WhenAll(allTasks);

    // Do stuff with result of completed tasks

    Return OK(calculatedResult);
}

在上面的方法中,您几乎可以同时发送所有查询,而无需等待响应。只有在发送所有查询后才开始等待响应 在所有查询结果到达后,您可以处理数据 - 所有操作都将在一个线程上执行。