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

EF Core 7重复生成Nullable DateTime字段迁移问题求助

问题描述

我拥有包含可空UpdatedDate字段的实体,相关实体初始化代码如下:

var defaultPolicy = new MatchingPolicy()
{
    Id = Guid.Parse("5cf3f8e5-50e1-47c8-aa42-40b1824ea099"),
    CompanyId = null,
    Name = "Name",
    Status = MatchingPolicyStatus.Draft,
    Type = MatchingPolicyType.Default,
    Description = "Blabla.",
    CreatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc).AddTicks(1258),
};

var defaultPolicyVersion = new MatchingPolicyVersion()
{
    Id = Guid.Parse("5cf3f8e5-50e1-47c8-aa42-40b1824ea098"),
    CreatedByUserName = "System",
    MatchingPolicyId = defaultPolicy.Id,
    ReviewerUserName = "System",
    Status = MatchingPolicyApprovalStatus.Approved,
    Version = 1,
    CreatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc),
    UpdatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc),
};

var defaultGroups = new[]
{
     new MatchingPolicyGroup
     {
         Id = Guid.Parse("1e93b3f9-4ed8-4b90-a859-31b6503ec89f"),
         MatchingPolicyVersionId = defaultPolicyVersion.Id,
         Group = MatchingPolicyGroupType.Full,
         CreatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc).AddTicks(1258),
     },
     new MatchingPolicyGroup
     {
         Id = Guid.Parse("b08f004f-a62d-409e-8025-337f0eb73054"),
         MatchingPolicyVersionId = defaultPolicyVersion.Id,
         Group = MatchingPolicyGroupType.Possible,
         CreatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc).AddTicks(1258),
     },
};

通过以下代码使用HasData将数据添加到数据库:

modelBuilder.Entity<MatchingPolicy>().HasData(defaultPolicy);
modelBuilder.Entity<MatchingPolicyVersion>().HasData(defaultPolicyVersion);
entity.HasData(defaultGroups);
modelBuilder.Entity<Scheme>().Property(u => u.MatchingPolicyId).HasDefaultValue(defaultPolicy.Id);

但EF Core 7始终重复生成相同的迁移,持续更新UpdatedDate字段,即使该迁移已存在。生成的迁移核心代码示例如下:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.UpdateData(
        table: "matching_policies",
        keyColumn: "id",
        keyValue: new Guid("5cf3f8e5-50e1-47c8-aa42-40b1824ea099"),
        column: "updated_date",
        value: null);

    migrationBuilder.UpdateData(
        table: "matching_policy_versions",
        keyColumn: "id",
        keyValue: new Guid("5cf3f8e5-50e1-47c8-aa42-40b1824ea098"),
        column: "updated_date",
        value: new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc));

    // 其余matching_policy_groups、matching_rule_templates的UpdateData代码省略
}

已尝试在模型构建器中直接设置字段可空、添加NonGeneratedValue、手动指定DateTime值或设为null,但问题依旧。

解决方案

1. 显式指定种子数据中的UpdatedDate值

对于未显式设置UpdatedDate的实体(如MatchingPolicy、MatchingPolicyGroup),在种子数据初始化时显式将UpdatedDate设为null,消除EF Core对比种子数据与数据库快照时的歧义(未赋值的可空字段会被视为需要更新为默认值)。

修改后的实体初始化示例:

var defaultPolicy = new MatchingPolicy()
{
    // 原有属性...
    CreatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc).AddTicks(1258),
    UpdatedDate = null // 显式指定null
};

var defaultGroups = new[]
{
     new MatchingPolicyGroup
     {
         // 原有属性...
         CreatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc).AddTicks(1258),
         UpdatedDate = null // 显式指定null
     },
     // 第二个Group同理
};

2. 检查并修正数据库快照定义

打开项目中的YourDbContextModelSnapshot.cs文件,确认UpdatedDate字段的定义与实体一致:

  • 确认字段标记为可空(IsNullable = true)
  • 确认没有多余的生成规则(如ValueGeneratedOnAddOrUpdate)

若快照定义有误,手动修正后重新生成迁移。

3. 使用HasDefaultValueSql管理默认值

如果UpdatedDate需要默认值,避免用HasDefaultValue硬编码固定值,改用HasDefaultValueSql让数据库处理默认逻辑:

modelBuilder.Entity<MatchingPolicy>()
    .Property(u => u.UpdatedDate)
    .HasDefaultValueSql("NULL"); // 或根据业务需求使用CURRENT_TIMESTAMP等

4. 清理并重新生成数据库快照

若上述方法无效,尝试重置迁移环境:

  1. 删除Migrations目录下的所有迁移文件
  2. 删除YourDbContextModelSnapshot.cs文件
  3. 运行命令重新生成初始迁移:
dotnet ef migrations add InitialCreate
  1. 更新数据库:
dotnet ef database update

5. 排除特定字段的种子数据跟踪

如果UpdatedDate不需要在种子数据中维护,可在模型配置中排除该字段的对比逻辑:

modelBuilder.Entity<MatchingPolicy>()
    .HasData(defaultPolicy)
    .Ignore(u => u.UpdatedDate); // 从种子数据对比中排除该字段

此方法会让EF Core永远不为该字段生成迁移更新,适合不需要固定种子值的可空字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 22:25:20