How to Add a New Database Provider to OpenDeepWiki: A Complete Implementation Guide
To add a new database provider to OpenDeepWiki, create a new project implementing the DbContext, IContextFactory, and ServiceCollectionExtensions following the naming convention AddOpenDeepWiki{Provider}, then register it in DatabaseServiceExtensions.cs to enable dynamic loading via configuration.
OpenDeepWiki uses a modular architecture based on dependency injection and dynamic assembly loading to support multiple database backends. This guide walks you through the exact steps to add a new database provider to OpenDeepWiki, following the established patterns used for SQLite and PostgreSQL implementations.
Understanding the Database Provider Architecture
Core Components
The architecture centers on three abstractions defined in the main project:
MasterDbContext: The base DbContext that all providers must inherit fromIContext: Interface abstracting database operationsIContextFactory: Factory interface for creating database contexts
Each provider lives in its own project under src/EFCore/ (e.g., OpenDeepWiki.Sqlite, OpenDeepWiki.Postgresql).
Dynamic Loading Mechanism
The entry point src/OpenDeepWiki/Infrastructure/DatabaseServiceExtensions.cs orchestrates provider selection through configuration:
- Reads
Database:Typefromappsettings.jsonor theDB_TYPEenvironment variable - Dynamically loads the corresponding assembly using
Assembly.Load - Reflectively invokes the extension method
AddOpenDeepWiki{Provider}to register services
This design allows adding new database support without modifying the core application code—only configuration changes are needed at runtime.
Step-by-Step Implementation Guide
Step 1: Create the Provider Project
Create a new class library project in src/EFCore/OpenDeepWiki.MySql (replace "MySql" with your target database).
Add the required NuGet packages for your EF Core provider (e.g., Pomelo.EntityFrameworkCore.MySql for MySQL) and add a project reference to the main OpenDeepWiki project.
Step 2: Implement the DbContext
Create a DbContext that inherits from MasterDbContext:
using Microsoft.EntityFrameworkCore;
using OpenDeepWiki.EFCore;
namespace OpenDeepWiki.MySql;
public class MySqlDbContext : MasterDbContext
{
public MySqlDbContext(DbContextOptions<MySqlDbContext> options)
: base(options)
{
}
}
Step 3: Implement the ContextFactory
Implement IContextFactory to handle context creation:
using Microsoft.EntityFrameworkCore;
using OpenDeepWiki.EFCore;
namespace OpenDeepWiki.MySql;
public class MySqlContextFactory : IContextFactory
{
private readonly IDbContextFactory<MySqlDbContext> _factory;
public MySqlContextFactory(IDbContextFactory<MySqlDbContext> factory)
{
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}
public IContext CreateContext() => _factory.CreateDbContext();
}
Step 4: Create the ServiceCollection Extension
This is the critical integration point. The class name must follow the pattern {Provider}ServiceCollectionExtensions and the method must be named AddOpenDeepWiki{Provider}:
using Microsoft.EntityFrameworkCore;
using OpenDeepWiki.EFCore;
namespace OpenDeepWiki.MySql;
public static class MySqlServiceCollectionExtensions
{
public static IServiceCollection AddOpenDeepWikiMySql(
this IServiceCollection services,
string connectionString)
{
// Register pooled DbContext factory
services.AddPooledDbContextFactory<MySqlDbContext>(
options => options.UseMySql(
connectionString,
ServerVersion.AutoDetect(connectionString)));
// Register IContext for direct injection
services.AddScoped<IContext>(sp =>
sp.GetRequiredService<IDbContextFactory<MySqlDbContext>>()
.CreateDbContext());
// Register IContextFactory for factory pattern usage
services.AddSingleton<IContextFactory, MySqlContextFactory>();
return services;
}
}
Step 5: Register the Provider in DatabaseServiceExtensions
Modify src/OpenDeepWiki/Infrastructure/DatabaseServiceExtensions.cs to handle your new provider type. Add a case to the switch expression and implement the loading logic:
private static IServiceCollection AddMySql(IServiceCollection services, string connectionString)
{
var assembly = LoadProviderAssembly("OpenDeepWiki.MySql");
var extensionType = assembly.GetType("OpenDeepWiki.MySql.MySqlServiceCollectionExtensions")
?? throw new InvalidOperationException("找不到 MySqlServiceCollectionExtensions 类型");
var method = extensionType.GetMethod("AddOpenDeepWikiMySql")
?? throw new InvalidOperationException("找不到 AddOpenDeepWikiMySql 方法");
method.Invoke(null, [services, connectionString]);
return services;
}
Then update the switch expression in the main registration method:
return dbType switch
{
"sqlite" => AddSqlite(services, connectionString),
"postgresql" or "postgres" => AddPostgresql(services, connectionString),
"mysql" => AddMySql(services, connectionString), // 新增
_ => throw new InvalidOperationException($"不支持的数据库类型: {dbType}")
};
Step 6: Configure and Test
Update your appsettings.json to use the new provider:
{
"Database": {
"Type": "mysql"
},
"ConnectionStrings": {
"Default": "Server=localhost;Database=opendeepwiki;User=root;Password=yourpassword;"
}
}
Run the application to verify the dynamic loading works correctly:
dotnet run --project src/OpenDeepWiki/OpenDeepWiki.csproj
Key Implementation Details
Naming Conventions
The dynamic loading mechanism relies on strict naming conventions:
- Assembly name:
OpenDeepWiki.{Provider}(e.g.,OpenDeepWiki.MySql) - Extension class:
{Provider}ServiceCollectionExtensions(e.g.,MySqlServiceCollectionExtensions) - Extension method:
AddOpenDeepWiki{Provider}(e.g.,AddOpenDeepWikiMySql) - Configuration value: Lowercase provider name (e.g.,
"mysql","sqlite","postgresql")
Required Service Registrations
Every provider extension must register three core services:
AddPooledDbContextFactory<TContext>: Enables efficient DbContext poolingIContext: Scoped service for direct database accessIContextFactory: Singleton factory for creating contexts on demand
Failure to register any of these will result in runtime dependency resolution errors when the application attempts to instantiate repository classes.
Summary
- OpenDeepWiki uses dynamic assembly loading to support multiple database providers without recompiling the core application.
- To add a new database provider to OpenDeepWiki, create a new project under
src/EFCore/implementingMasterDbContext,IContextFactory, and theAddOpenDeepWiki{Provider}extension method. - Register the provider in
DatabaseServiceExtensions.csby adding a case to the switch expression and implementing the assembly loading logic. - Follow the strict naming conventions: assembly
OpenDeepWiki.{Provider}, class{Provider}ServiceCollectionExtensions, methodAddOpenDeepWiki{Provider}. - Configure the new provider via
Database:Typeinappsettings.jsonor theDB_TYPEenvironment variable.
Frequently Asked Questions
What is the minimum implementation required to add a new database provider to OpenDeepWiki?
At minimum, you must create a DbContext inheriting from MasterDbContext, implement IContextFactory for context creation, and provide a static extension method named AddOpenDeepWiki{Provider} in a class named {Provider}ServiceCollectionExtensions. This method must register AddPooledDbContextFactory, IContext, and IContextFactory with the dependency injection container.
Can I add a database provider without modifying the core OpenDeepWiki project?
No, you must modify src/OpenDeepWiki/Infrastructure/DatabaseServiceExtensions.cs to add a new case to the switch expression that handles your provider type. However, once registered, the provider assembly can be maintained independently, and the core application will dynamically load it at runtime based on configuration without requiring further code changes.
What naming convention must the extension method follow for dynamic loading to work?
The extension method must be named exactly AddOpenDeepWiki{Provider} where {Provider} matches the provider name used in the assembly OpenDeepWiki.{Provider} and the class {Provider}ServiceCollectionExtensions. For example, for MySQL, the method must be AddOpenDeepWikiMySql, the class MySqlServiceCollectionExtensions, and the assembly OpenDeepWiki.MySql. The configuration value should be lowercase: "mysql".
How does OpenDeepWiki handle database migrations for multiple providers?
Each database provider project maintains its own migrations folder within its project directory (e.g., src/EFCore/OpenDeepWiki.MySql/Migrations). When adding a new provider, you generate migrations using the EF Core CLI targeting your new project: dotnet ef migrations add Initial -p src/EFCore/OpenDeepWiki.MySql -s src/OpenDeepWiki. This keeps provider-specific SQL dialects isolated while allowing the core domain models to remain consistent across all providers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →