sqlite 单一上下文类型、多个提供程序

cetgtptt  于 2022-11-14  发布在  SQLite
关注(0)|答案(1)|浏览(168)

如何设置和配置实体框架核心以使用单个DbContext类并管理多个提供程序(SQL Server、Sqlite)的迁移?
我正在生产一个.NET6Blazor WASM项目,它托管在ASP.NETWeb API中,使用C#项目(客户端、API、逻辑、数据和共享项目)的标准体系结构。DbContext被注入到存储库中,然后在逻辑层中使用。一旦请求完成,服务和DbContext就会被释放。一切都很好。
我想创建一个配套的桌面应用程序(WinUi3),它使用相同的逻辑层和数据层,但使用SQLite数据提供程序。我可以使用从现有DbContext继承的新DbContext类,但是存储库不知道使用哪个DbContext
文档(针对多个提供程序和单个上下文)没有为SQLite提供程序提供新的ModelSnapshot。因此,为update-database生成的SQL代码仍然使用SQL Server的语法编写。
架构和配置:

Data.Migrations.csproj(项目仅用于迁移,如here所示):

  • 迁移(用于SQL Server提供程序的文件夹)
  • Migrations/Sqlite(SQLite提供程序的文件夹)

Data.csproj(包含DbContext和存储库的项目):

public class Context : DbContext
{
    protected readonly IConfiguration Configuration;

    public Context() { }

    public Context(DbContextOptions<Context> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // some model configuration
    }

    // DbSets...
}

public interface IRepository<T> where T : class
{
    // some interface methods
}

public class Repository<T> : IRepository<T> where T : class
{
    private DbSet<T> entities;

    public Repository()
    {
    }

    // implement some interface methods
}

public class DbContextFactory : IDesignTimeDbContextFactory<Context>
{
    public Context CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder<Context>();

        if (DbContextHelper.Provider == "SqlServer")
            optionsBuilder.UseSqlServer(DbContextHelper.ConnectionString,
                    x => x.MigrationsAssembly("Data.Migrations"));
        else if (DbContextHelper.Provider == "Sqlite")
            optionsBuilder.UseSqlite(DbContextHelper.ConnectionString,
                    x => x.MigrationsAssembly("Data.Migrations"));
        else
            throw new InvalidOperationException("Database provider not specified");

        return new Context(optionsBuilder.Options);
    }
}

Logic.csproj

public interface ICustomerService
{
    // some interface methods
}

public class CustomerService : ICustomerService
{
    protected readonly IRepository<Customer> _customerRepository;

    public CustomerService(IRepository<Customer> customerRepository)
    {
        _customerRepository = customerRepository;
    }

    // implement some interface methods
}

Api.csproj

// Program class

builder.Services.AddDbContext<Context>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("Context"),
    x => x.MigrationsAssembly("Data.Migrations"))
);

builder.Services.AddTransient<ICustomerService, CustomerService>();

builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
builder.Services.AddScoped<DbContext, Context>();

WinUi.csproj(WinUi 3 app~=UWP app):

// App.xaml.cs

public App()
{
    services.AddDbContext<InSpecContext, Context>(options =>
        options.UseSqlite(DbContextHelper.ConnectionString,
        x => x.MigrationsAssembly("Data.Migrations"))
    );
}
s71maibg

s71maibg1#

我最终摆脱了@PanagiotisKanavos发表的现已删除的评论所建议的存储库模式。
然后,我使用位于Data项目中的DbContext文件为我的每个提供程序创建了一个单独的迁移项目。
然后,在Logic服务中,我不是注入泛型存储库或DbContext,而是按照这里的建议注入IDbContextFactory<MyContext> factory
API的配置如下所示

builder.Services.AddDbContextFactory<Context>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("Context"),
    x => x.MigrationsAssembly("Data.SqlServer"))
);

WinUi应用的配置如下所示:

services.AddDbContextFactory<Context>(options =>
    options.UseSqlite(DbContextHelper.ConnectionString,
    x => x.MigrationsAssembly("Data.Sqlite"))
);

相关问题