EntityFrameworkCore SQLite in-memory db tables are not created
对于集成测试,我正在使用
Ensure that the database for the context exists. If it exists, no
action is taken. If it does not exist then the database and all its
schema are created. If the database exists, then no action is made to
ensure it is compatible with the model for this context.
我已经读到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<Startup> { protected override IWebHostBuilder CreateWebHostBuilder() { return WebHost.CreateDefaultBuilder() .UseStartup<Startup>(); } protected override void ConfigureWebHost(IWebHostBuilder builder) { using (var connection = new SqliteConnection("DataSource=MySharedInMemoryDb;mode=memory;cache=shared")) { connection.Open(); builder.ConfigureServices(services => { var serviceProvider = new ServiceCollection() .AddEntityFrameworkSqlite() .BuildServiceProvider(); services.AddDbContext<MyDbContext>(options => { options.UseSqlite(connection); options.UseInternalServiceProvider(serviceProvider); }); var contextServiceProvider = services.BuildServiceProvider(); // we need a scope to obtain a reference to the database contexts using (var scope = contextServiceProvider.CreateScope()) { var scopedProvider = scope.ServiceProvider; var logger = scopedProvider.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>(); using (var myDb = scopedProvider.GetRequiredService<MyDbContext>()) { // DEBUG CODE // this returns script to create db objects as expected // proving that MyDbContext is setup correctly var script = myDb.Database.GenerateCreateScript(); // DEBUG CODE // this does not create the db objects ( tables etc ) // this is not as expected and contrary to ms docs var result = myDb.Database.EnsureCreated(); try { SeedData.PopulateTestData(myDb); } catch (Exception e) { // exception is thrown that tables don't exist logger.LogError(e, $"SeedData.PopulateTestData(myDb) threw exception=[{e.Message}]"); } } } }); } builder.UseContentRoot("."); base.ConfigureWebHost(builder); } |
请注意,在这篇文章中,我只是在问为什么
使用非共享 SQLite 内存数据库
SQLite 内存数据库默认是瞬态的。正如文档所述:
The database ceases to exist as soon as the database connection is closed. Every :memory: database is distinct from every other.
另一方面,
EF Core 的
因此,为了在 EF Core 中跨多个调用使用相同的 SQLite 内存数据库,您需要单独创建一个
例如:
1 2 3 4 5 6 7 | var keepAliveConnection = new SqliteConnection("DataSource=:memory:"); keepAliveConnection.Open(); services.AddDbContext<MyContext>(options => { options.UseSqlite(keepAliveConnection); }); |
请注意,
顺便说一句,这是 EF Core 文档中当前使用的关于如何使用 SQLite 内存数据库进行测试的方法。
使用共享的 SQLite 内存数据库
SQLite 还支持命名的共享内存数据库。通过使用相同的连接字符串,多个
The database is automatically deleted and memory is reclaimed when the last connection to the database closes.
因此,仍然需要维护一个单独的打开连接对象,以便数据库可以跨多个 EF Core 调用使用。例如:
1 2 3 4 5 6 7 8 | var connectionString ="DataSource=myshareddb;mode=memory;cache=shared"; var keepAliveConnection = new SqliteConnection(connectionString); keepAliveConnection.Open(); services.AddDbContext<MyContext>(options => { options.UseSqlite(connectionString); }); |
请注意,这种方法不限于单个线程,因为每个