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 from
  • IContext: Interface abstracting database operations
  • IContextFactory: 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:

  1. Reads Database:Type from appsettings.json or the DB_TYPE environment variable
  2. Dynamically loads the corresponding assembly using Assembly.Load
  3. 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:

  1. AddPooledDbContextFactory<TContext>: Enables efficient DbContext pooling
  2. IContext: Scoped service for direct database access
  3. IContextFactory: 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/ implementing MasterDbContext, IContextFactory, and the AddOpenDeepWiki{Provider} extension method.
  • Register the provider in DatabaseServiceExtensions.cs by adding a case to the switch expression and implementing the assembly loading logic.
  • Follow the strict naming conventions: assembly OpenDeepWiki.{Provider}, class {Provider}ServiceCollectionExtensions, method AddOpenDeepWiki{Provider}.
  • Configure the new provider via Database:Type in appsettings.json or the DB_TYPE environment 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →