如何配置Entity Framework Core内存数据库

Lie*_*ero 5 unit-testing entity-framework dependency-injection entity-framework-core .net-core

我想在每个单元测试中创建干净的内存数据库。当我运行多个测试时,以前测试中的数据仍保留在数据库中。如何处理现有的内存数据库?

我使用以下代码初始化每个测试:

 [TestInitialize]
 public void TestInitialize()
 {
     Services = new ServiceCollection();
     Services.AddScoped<DbContextOptions<MyDbContext>>(sp => new DbContextOptionsBuilder<TacsDbContext>()
             .UseInMemoryDatabase("MyTestDbContext")
             .Options);

     Services.AddTransient<InMemoryMyDbContext>();
     Services.AddTransient<MyDbContext>(sp => sp.GetService<InMemoryTacsDbContext>());

    ServiceProvider = Services.BuildServiceProvider();
 }

 [TestMethod]
 public void Test1()
 {
     using (var dbContext = ServiceProvider.GetService<MyDbContext>()) ...
 }

 [TestMethod]
 public void Test2()
 {
     using (var dbContext = ServiceProvider.GetService<MyDbContext>()) ...
 }
Run Code Online (Sandbox Code Playgroud)

我使用.NET Core 2.0和Entity Framework Core 2.0

编辑 我无法使用标准注册:Services.AddDbContext<InMemoryMyDbContext>(...),因为

public class InMemoryMyDbContext : MyDbContext
{
    public InMemoryMyDbContext(DbContextOptions<InMemoryMyDbContext> options)
      : base(options) { }  //compiler error

    public InMemoryMyDbContext(DbContextOptions<MyDbContext> options)
      : base(options) { }  //runtime IoC error
}

public class MyDbContext : DbContext
{
    public MyDbContext(DbContextOptions<MyDbContext> options)
      : base(options) { } 
}
Run Code Online (Sandbox Code Playgroud)

Lie*_*ero 2

好的,我的例子的解决方案是调用DbContextOptionsBuilder.UseApplicationServiceProvider()

Services.AddScoped<DbContextOptions<MyDbContext>>(sp => new DbContextOptionsBuilder<MyDbContext>()
        .UseApplicationServiceProvider(sp)
        .UseInMemoryDatabase("Test")
        .Options);
Run Code Online (Sandbox Code Playgroud)

当您以通常的方式设置 ServiceCollection 时,会自动调用此方法,因此在以下情况下,每次都会从头开始创建数据库

Services.AddDbContext<MyDbContext>(options => options.UseInMemoryDatabase("Test"));
Run Code Online (Sandbox Code Playgroud)

最后,我能够修改 MyDbContext 以便调用上面的行:

public class MyDbContext : DbContext
{
    protected MyDbContext (DbContextOptions options) : base(options) { }

    public MyDbContext (DbContextOptions<MyDbContext> options) 
       : this((DbContextOptions)options) { }
}

public class InMemoryMyDbContext : MyDbContext
{
    public InMemoryMyDbContext (DbContextOptions<InMemoryTacsDbContext> options) 
        : base(options) { } 
}

Services.AddDbContext<InMemoryMyDbContext>(options => 
    options.UseInMemoryDatabase("Test"), ServiceLifetime.Transient);
Services.AddTransient<MyDbContext>(sp => sp.GetService<InMemoryMyDbContext>());
Run Code Online (Sandbox Code Playgroud)