首页 > 解决方案 > 如何使用 Entity Framework 处理多种数据库类型支持

问题描述

我需要在项目中支持 MariaDb 和 SqlServer 的迁移。目前,我编辑了由 add-migration 命令创建的迁移文件。您可以看到迁移文件的某些部分。

migrationBuilder.CreateTable(
            name: "Tbl1",
            columns: table => new
            {
                Id = table.Column<long>(nullable: false)
                    .Annotation("SqlServer:Identity", "1, 1")
                    .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
                Name = table.Column<string>(maxLength: 100, nullable: true),
                Measurement = table.Column<string>(maxLength: 100, nullable: true),
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Tbl1", x => x.Id);
            });

通过该更改,我的迁移文件可以支持两种数据库类型(MariaDb 和 SqlServer)。但是,我必须为两者设置和使用相同的 ColumnType。我想知道 Entityframework 是否提供了任何最佳实践来支持多种数据库类型?

标签: sql-serverasp.net-coreentity-framework-coremariadb

解决方案


看看Migrations with Multiple Providers,它使用以下两种方法准确讨论了该场景:

两个迁移集

在第一种方法中,您为每个模型更改生成两个迁移。

一种方法是将每个迁移集放在一个单独的程序集中,并在添加两个迁移之间手动切换活动提供程序(和迁移程序集)。

使使用这些工具更容易的另一种方法是创建一个派生自 DbContext 并覆盖活动提供程序的新类型。此类型在设计时添加或应用迁移时使用。

class MySqliteDbContext : MyDbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite("Data Source=my.db");
}

笔记

由于每个迁移集都使用自己的 DbContext 类型,因此这种方法不需要使用单独的迁移程序集。

dotnet ef migrations add InitialCreate --context MyDbContext --output-dir Migrations/SqlServerMigrations
dotnet ef migrations add InitialCreate --context MySqliteDbContext --output-dir Migrations/SqliteMigrations

一套迁移

如果您不喜欢有两组迁移,您可以手动将它们组合成一个可应用于两个提供程序的集合。

注释可以共存,因为提供者会忽略它不理解的任何注释。例如,与 Microsoft SQL Server 和 SQLite 一起使用的主键列可能如下所示。

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

如果操作只能应用于一个提供者,或者它们在提供者之间不同,请使用 ActiveProvider 属性来确定哪个提供者处于活动状态:

if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.SqlServer")
{
    migrationBuilder.CreateSequence(
        name: "EntityFrameworkHiLoSequence");
}

Pomelo.EntityFrameworkCore.MySql 具体

另请参阅实现当前行为的替代方案以始终抛出,如果已为对象 #982 设置架构以及有关如何处理这种情况的参考,MySQL 和 MariaDB 不知道 SQL Server 架构(例如dbo)是什么(假设您使用 Pomelo.EntityFrameworkCore.MySql作为提供程序来访问 MariaDB 数据库)。

以下是一些代码选项:

// Throw an exception, if a schema is being used. This is the default.
options.UseMySql(myConnectionString, b => b.SchemaBehavior(MySqlSchemaBehavior.Throw))

// Silently ignore any schema definitions.
options.UseMySql(myConnectionString, b => b.SchemaBehavior(MySqlSchemaBehavior.Ignore))

// Use the specified translator delegate to translate from an input schema and object name to
// an output object name whenever a schema is being used.
options.UseMySql(myConnectionString, b => b.SchemaBehavior(MySqlSchemaBehavior.Translate,
    (schema, entity) => $"{schema ?? "dbo"}_{entity}"))

推荐阅读