Now I want to create the database in each provider (Sqlite, MsSql, Postgresql, Mongo)
Let’s say that I have the database context
public partial class EmpContext : DbContext
{
public EmpContext()
{
}
public EmpContext(DbContextOptions<EmpContext> options)
: base(options)
{
}
public virtual DbSet<Department> Department { get; set; }
public virtual DbSet<Employee> Employee { get; set; }
}
and I want to create the database from a simple connection string
For this I need a common interface , IEFCore_DatabasePlugin, to function the same for all database
public interface IEFCore_DatabasePlugin : IDatabasePlugin
{
DbContextOptionsBuilder<T> GenerateDbContextOptionsBuilder<T>(string connectionString, string? databaseName = null)
where T : DbContext;
DbContextOptionsBuilder<T> UsePlugin<T>(DbContextOptionsBuilder<T> optionBuilder,string connectionString, string? databaseName = null)
where T : DbContext;
}
I target .NET 10 and Entity Framework Core 10.0.11. I support SQL Server,
PostgreSQL, SQLite, and MongoDB while keeping my application-facing code the
same.
How the solution is used
I demonstrate the intended usage in my tests: I choose a plugin, build options
for my application context, create the database when necessary, and then use
the context normally. I keep the provider-specific part in the setup code.
SQLite example
My SQLite test creates a unique temporary file and builds a connection string
for it:
var databasePath = Path.Combine(
Path.GetTempPath(),
$"efcore_dain_sqlite_{Guid.NewGuid():N}.db");
var connectionString =
new SqliteConnectionStringBuilder
{
DataSource = databasePath
}.ConnectionString;
I select the SQLite plugin and ask it to configure `EmpContext`:
IEFCore_DatabasePlugin plugin = new SqliteEfCorePlugin();
var optionsBuilder =
plugin.GenerateDbContextOptionsBuilder<EmpContext>(
connectionString,
databasePath);
using var context = new EmpContext(optionsBuilder.Options);
context.Database.EnsureCreated();
Assert.True(File.Exists(databasePath));
`EnsureCreated` exercises my complete path: the plugin selects SQLite, EF Core
receives the configured options, and EF Core creates the database from my
`EmpContext` model. I then verify the observable result by checking that the
file exists. My context contains no SQLite-specific configuration.
SQL Server, PostgreSQL, and MongoDB example
My container tests use the same context setup, but obtain the connection string
from a Testcontainers-managed database:
var connectionString = dockerContainer.GetConnectionString();
var optionsBuilder =
plugin.GenerateDbContextOptionsBuilder<EmpContext>(
connectionString,
"EmpContextDatabase");
using var context = new EmpContext(optionsBuilder.Options);
context.Database.EnsureCreated();
Takeaways
My main design choice is to isolate provider configuration, not to hide every
database difference. I keep connection-string rules and EF Core extension
methods in the provider packages, while my application depends on a small,
stable plugin contract.