EF Core - SQLServer 迁移是否适用于 SQLite



我有一个简单的项目,我最初使用 SQL Server 作为后端,使用 EF Core 和代码优先方法(遵循本教程:https://learn.microsoft.com/en-us/ef/core/get-started/aspnetcore/new-db)

现在我想将实现切换到SQLite。我想我可以从SQL Server运行数据库创建的初始迁移并将其应用于SQLite。似乎它无法正常工作:例如。主键上的自动增量没有应用,然后我看到一些不一致(sqlite抱怨应该'INTEGER' 'int')等。

那么,这是否意味着迁移依赖于后端?如果是,那么不应该在嵌套文件夹中创建它们(例如。 ./Migrations/SQLServer )?

谁能解释一下这是如何工作的?

注意:抱歉,我是 EF 代码优先和迁移的新手...谢谢!

Add-Migration/dotnet ef migrations add 命令生成的迁移是特定于后端的,但您可以手动编辑它们以使其与多个后端兼容。最简单的方法是生成两组迁移,如@alwayslearning的回答中所述,然后将它们合并为一个迁移集。

例如,Id列可能如下所示:

Id = table.Column<int>(nullable: false)
    .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
    .Annotation("Sqlite:Autoincrement", true);

您还可以有条件地执行后端之间可能根本不同的操作:

if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.SqlServer")
{
    // TODO
}
else if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.Sqlite")
{
    // TODO
}

是的,迁移取决于后端。每个后端都有其细节,因此迁移通常具有后端细节,例如列规范。

在某些ORM中,可以以抽象方式映射"代码优先"模型,并让后端特定的提供者将此抽象模型映射到后端特定类型,但在任何相对复杂的模型中,很难保持整个映射后端的独立性。

要迁移到 SQLite,您可以更改 Startup 中的配置.cs将 DbContext 注册为类似

services.AddDbContext<YourContext>(options => options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")))

然后,可以使用"dotnet ef migrations add"命令指定迁移的显式路径。此问题包含有关设置显式文件夹路径的更多详细信息。

public class CompositeMigrationsAnnotationsProvider : IMigrationsAnnotationProvider
{
    private readonly IMigrationsAnnotationProvider[] _providers;
    public CompositeMigrationsAnnotationsProvider(MigrationsAnnotationProviderDependencies dependencies)
    {
        _providers = new IMigrationsAnnotationProvider[] {
            new SqlServerMigrationsAnnotationProvider(dependencies),
            new SqliteMigrationsAnnotationProvider(dependencies) 
        };
    }
    public IEnumerable<IAnnotation> For(IModel model) => _providers.SelectMany(p => p.For(model));
    public IEnumerable<IAnnotation> For(IProperty property) => _providers.SelectMany(p => p.For(property));
    public IEnumerable<IAnnotation> For(IIndex index) => _providers.SelectMany(p => p.For(index));
    public IEnumerable<IAnnotation> For(IKey key) => _providers.SelectMany(p => p.For(key));
    public IEnumerable<IAnnotation> For(IForeignKey foreignKey) => _providers.SelectMany(p => p.For(foreignKey));
    public IEnumerable<IAnnotation> For(IEntityType entityType) => _providers.SelectMany(p => p.For(entityType));
    public IEnumerable<IAnnotation> For(ISequence sequence) => _providers.SelectMany(p => p.For(sequence));
    public IEnumerable<IAnnotation> For(ICheckConstraint checkConstraint) => _providers.SelectMany(p => p.For(checkConstraint)); //EF Core 3.x
    public IEnumerable<IAnnotation> ForRemove(IModel model) => _providers.SelectMany(p => p.ForRemove(model));
    public IEnumerable<IAnnotation> ForRemove(IIndex index) => _providers.SelectMany(p => p.ForRemove(index));
    public IEnumerable<IAnnotation> ForRemove(IProperty property) => _providers.SelectMany(p => p.ForRemove(property));
    public IEnumerable<IAnnotation> ForRemove(IKey key) => _providers.SelectMany(p => p.ForRemove(key));
    public IEnumerable<IAnnotation> ForRemove(IForeignKey foreignKey) => _providers.SelectMany(p => p.ForRemove(foreignKey));
    public IEnumerable<IAnnotation> ForRemove(IEntityType entityType) => _providers.SelectMany(p => p.ForRemove(entityType));
    public IEnumerable<IAnnotation> ForRemove(ISequence sequence) => _providers.SelectMany(p => p.ForRemove(sequence));
    public IEnumerable<IAnnotation> ForRemove(ICheckConstraint checkConstraint) => _providers.SelectMany(p => p.ForRemove(checkConstraint)); //EF Core 3.x
}
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.ReplaceService<IMigrationsAnnotationProvider, CompositeMigrationsAnnotationsProvider>();
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.UseIdentityColumns(); //EF Core 3.x
        modelBuilder.ForSqlServerUseIdentityColumns(); //EF Core 2.x
    }
}

最新更新