使用Simple Injector和WinForms中的后台工作程序使用EF6保存到DB

时间:2017-03-31 15:08:32

标签: asp.net winforms dependency-injection entity-framework-6 simple-injector

我已经获得了一个旧的WinForms应用程序来更新和改进。我正在尝试使用SimpleInjector添加DI。我习惯了.Net MVC,但这是我第一次使用WinForms。

该应用程序使用了很多BackGround worker。我的理解是,这是WinForms特有的,每个后台工作者都会创建一个新线程。

我认为我的问题是,当我想使用EF6将数据保存到数据库时,由于多线程,SaveChanges方法无法保存。

My SimpleInjector容器设置如下

_container = new Container();
_container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();

// Register DbContext
_container.Register<DbContext, MyDbContext>(Lifestyle.Scoped);

当我在dbContext上调用SaveChanges时,得到的结果为0,表示没有记录保存到数据库中。在我的调试器中,我得到一个错误,说DbContext已经被处理掉了。如果在保存之前发生这种情况,它解释了为什么从SaveChanges返回0。不幸的是,之前的开发人员捕获了每个异常,因此应用程序正在尝试处理每个错误,这使得故障排除变得困难并导致意外行为。

我期望为每个线程创建一个新的DbContext,并且SaveChanges将保存每个线程中所做的更改,以便在一个上下文中发生的事情不会影响其他线程中的其他DbContexts。

当我从数据库中读取数据时,我在每个方法中手动创建一个新的DbContext。是否有可能当使用块完成时它正在处理DbContext?

using (var newDbContext = new MyDbContext())
{
    return newDbContext.Set<TableA>().First(x => x.Id == id);
}

我希望如果我正确配置了SimpleInjector,我也不需要这样做。

我在这个阶段有点迷失,并认为我可能没有正确理解文档,任何建议将不胜感激。提前谢谢。

1 个答案:

答案 0 :(得分:2)

  

我期待为每个线程创建一个新的DbContext

这不是TheadScopedLifestyle的工作原理。使用ThreadScopedLifestyle,在显式启动的Scope的上下文中将有一个注册实例,并且此范围是特定于线程的。这意味着一个线程可以拥有该服务的许多实例,因为线程可以存活很长时间,而Scope通常只能存活很短的时间。

ThreadScopedLifestyle的典型用法如下:

void MethodThatRunsInABackGroundThread()
{
    using (ThreadScopedLifestyle.BeginScope(container))
    {
        var service = container.GetInstance<ISomeService>();
        service.DoWork();
    }
}

当您在活动范围外解析Scoped个实例(或包含范围实例的某些对象图)时,Simple Injector将抛出异常。