You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让EF迁移为枚举种子数据生成单独InsertData语句以支持SQL Server 2005?

EF迁移生成单条INSERT兼容SQL Server 2005的解决方案

背景

我有枚举类型FooNames,需要将其值作为种子数据填充到关联的数据库表Foo中。实体类Foo和枚举FooNames的定义如下:

实体类Foo

class Foo
{
    [Key]
    [Index("pk")]
    [Column("id")]
    [DatabaseGenerated(DatabaseGeneratedOption.None)] // 强制EF迁移不生成自增列
    public int Id { get; set; }

    [Required]
    [Column("description", TypeName = "varchar")]
    [MaxLength(50)]
    public string Description { get; set; }
}

枚举FooNames

enum FooNames
{
    Created = 1,
    Pending,
    Approved,
    Reconciled,
    Cancelled,
    Failed,
    Error
}

在DbContext的OnModelCreating()方法中,我通过循环枚举值添加种子数据:

foreach (FooNames name in Enum.GetValues(typeof(FooNames)))
{
    modelBuilder.Entity<Foo>().HasData(new Foo
    {
        Id = (int)name,
        Description = name.ToString()
    });
}

但EF迁移生成的是单条多行INSERT语句,而SQL Server 2005不支持这种语法:

migrationBuilder.InsertData(
        table: "Foo",
        columns: new[] { "id", "description" },
        values: new object[,]
        {
            { 1, "Created" },
            { 2, "Pending" },
            { 3, "Approved" },
            { 4, "Reconciled" },
            { 5, "Cancelled" },
            { 6, "Failed" },
            { 7, "Error" }
        });

需要让EF为每个枚举值生成独立的migrationBuilder.InsertData()调用。


解决方案

方法1:手动修改迁移文件(简单直接)

生成迁移文件后,将自动生成的多行InsertData代码拆分为多个独立的InsertData调用,每个对应一个枚举值:

// 每个枚举值对应一条InsertData
migrationBuilder.InsertData(
    table: "Foo",
    columns: new[] { "id", "description" },
    values: new object[] { 1, "Created" });

migrationBuilder.InsertData(
    table: "Foo",
    columns: new[] { "id", "description" },
    values: new object[] { 2, "Pending" });

migrationBuilder.InsertData(
    table: "Foo",
    columns: new[] { "id", "description" },
    values: new object[] { 3, "Approved" });

migrationBuilder.InsertData(
    table: "Foo",
    columns: new[] { "id", "description" },
    values: new object[] { 4, "Reconciled" });

migrationBuilder.InsertData(
    table: "Foo",
    columns: new[] { "id", "description" },
    values: new object[] { 5, "Cancelled" });

migrationBuilder.InsertData(
    table: "Foo",
    columns: new[] { "id", "description" },
    values: new object[] { 6, "Failed" });

migrationBuilder.InsertData(
    table: "Foo",
    columns: new[] { "id", "description" },
    values: new object[] { 7, "Error" });

这种方式无需额外代码修改,适合一次性需求。

方法2:自定义迁移SQL生成器(长期兼容)

如果需要长期适配SQL Server 2005,避免每次手动修改迁移文件,可以自定义迁移SQL生成器,强制生成单条INSERT语句:

1. 创建自定义生成器类

using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Sql;

public class SqlServer2005MigrationsSqlGenerator : SqlServerMigrationsSqlGenerator
{
    public SqlServer2005MigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies)
        : base(dependencies)
    {
    }

    protected override void Generate(InsertDataOperation operation)
    {
        // 遍历每个种子数据,生成独立的INSERT语句
        foreach (var valueSet in operation.Values)
        {
            var singleInsert = new InsertDataOperation
            {
                Table = operation.Table,
                Schema = operation.Schema,
                Columns = operation.Columns,
                Values = new[] { valueSet }
            };
            base.Generate(singleInsert);
        }
    }
}

2. 注册自定义生成器

在DbContext的OnConfiguring方法中替换默认的迁移SQL生成器:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer("你的数据库连接字符串")
                  .ReplaceService<IMigrationsSqlGenerator, SqlServer2005MigrationsSqlGenerator>();
}

之后生成的迁移文件会自动为每个种子数据生成独立的InsertData调用,无需手动调整。


内容的提问来源于stack exchange,提问作者Codesmith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 12:32:02