诀窍是为 dev 创建一个单独的 dbcontext,让它继承主 dbcontext 并只更改连接字符串。
从那里开始,为主要 + 开发 dbcontexts 生成迁移,然后根据环境选择要使用的上下文。
代码设置
主 dbcontext 将使用依赖注入来获取包含您的连接字符串的配置。
using app.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
namespace app.Data
{
public class AppDbContext : DbContext
{
protected readonly IConfiguration Configuration;
public AppDbContext(IConfiguration config)
{
Configuration = config;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlServer(Configuration["SQLConnectionString"]);
}
// whatever your app does
public DbSet<Dog> Dogs { get; set; }
}
}
dev dbcontext 将只继承主要的,使用不同的配置块来指定 sqlite。
using app.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
namespace app.Data
{
public class DevAppDbContext : AppDbContext
{
public DevAppDbContext(IConfiguration config) : base(config)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlite(Configuration.GetConnectionString("app"));
}
}
}
我们将添加开发数据库连接字符串到我们的appsettings.Development.json
...
"ConnectionStrings": {
"app": "Data Source=app.db"
}
}
在 startup.cs 中,我们将通过依赖注入添加 IWebHostEnvironment 以获取环境。如果在 dev 中,那么我们将指定额外的泛型参数,将 dev dbcontext 指定为实现。
从 vscode 的文档中,方法签名是:
public static IServiceCollection AddDbContext<TContextService, TContextImplementation>
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
_config = configuration;
_env = env;
}
private readonly IConfiguration _config;
private readonly IWebHostEnvironment _env;
public void ConfigureServices(IServiceCollection services)
{
if (_env.IsDevelopment())
services.AddDbContext<AppDbContext, DevAppDbContext>();
else
services.AddDbContext<AppDbContext>();
services.AddDatabaseDeveloperPageExceptionFilter();
添加迁移
现在添加迁移需要切换环境并指定我们为其创建迁移的 dbcontext。这可以抽象为一个相当简单的 powershell 脚本:
[CmdletBinding()]
param(
[string]$Name
);
$prev = $Env:ASPNETCORE_ENVIRONMENT;
Write-Host "Previous env=""$prev""";
try {
Write-Host "Adding migration for production";
$Env:ASPNETCORE_ENVIRONMENT = "Production";
dotnet ef migrations add $Name `
--context "AppDbContext" `
--output-dir "Migrations/SqlServerMigrations";
Write-Host "Adding migration for development";
$Env:ASPNETCORE_ENVIRONMENT = "Development";
dotnet ef migrations add $Name `
--context "DevAppDbContext" `
--output-dir "Migrations/SqliteMigrations";
}
finally {
Write-Host "Restoring env=""$prev""";
$Env:ASPNETCORE_ENVIRONMENT = $prev;
}
示例用法:
> .\scripts\add-migration.ps1 -Name init
Previous env=""
Adding migration for production
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
Adding migration for development
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
Restoring env=""
应用迁移
与创建迁移一样,我们需要根据环境切换上下文。不过这一次,我们只会更新用户在调用脚本时指定的单个环境。
[CmdletBinding()]
param(
[string]
[ValidateSet("Development", "Production")]
$Environment
)
$context = @{
"Development" = "DevAppDbContext"
"Production" = "AppDbContext"
}.$Environment;
$prev=$Env:ASPNETCORE_ENVIRONMENT;
try {
$Env:ASPNETCORE_ENVIRONMENT=$Environment;
dotnet ef database update --context $context;
}
finally {
Write-Host "Restoring env=""$prev""";
$Env:ASPNETCORE_ENVIRONMENT = $prev;
}
使用示例:
> .\scripts\apply-migrations.ps1 -Environment Development
Setting environment to Development
Build started...
Build succeeded.
No migrations were applied. The database is already up to date.
Done.
Restoring env=""
结论
这应该足以开始使用 sqlite 进行本地开发,使用 sqlserver 进行实时开发。这种方法的一些限制是 sqlite 不支持 sqlserver 的所有功能,因此您必须同时设置一个 dev sqlserver db,或者需要决定避免使用这些功能。
进一步阅读