【问题标题】:Code-first migration: How to set default value for new property?代码优先迁移:如何为新属性设置默认值?
【发布时间】:2015-09-10 14:54:00
【问题描述】:

我正在使用 EF6 在我的数据库中存储 report 类的实例。数据库已经包含数据。假设我想给report添加一个属性,

public class report {
    // ... some previous properties

    // ... new property:
    public string newProperty{ get; set; }
}

现在如果我去包管理控制台并执行

add-migration Report-added-newProperty
update-database

我将在“/Migrations”文件夹中获得一个文件,将newProperty 列添加到表中。这工作正常。但是,在数据库中较旧的条目上,newProperty 的值现在是一个空字符串。但我希望它是,例如,“旧的”。

所以我的问题是:如何在迁移脚本(或其他地方)中为新属性(任何类型)设置默认值?

【问题讨论】:

  • 这里的行为不是由于实体框架而是TSQL。当您在 TSQL 中添加一个新的可空列时,必须使用 WITH VALUES 来指定现有记录的值(请参阅此 question)。此处答案中给出的解决方法是使该列不可为空。另一种选择是定义自定义 DefaultValue 属性,例如 this

标签: c# .net entity-framework entity-framework-6 entity-framework-migrations


【解决方案1】:

如果您看到生成的迁移代码,您将看到AddColumn

AddColumn("dbo.report", "newProperty", c => c.String(nullable: false));

你可以加defaultValue

AddColumn("dbo.report", "newProperty", 
           c => c.String(nullable: false, defaultValue: "old"));

或添加defaultValueSql

AddColumn("dbo.report", "newProperty",
           c => c.String(nullable: false, defaultValueSql: "GETDATE()"));

【讨论】:

  • 如果它正确地拉入代码优先模型中定义的 [DefaultValue(xyz)] 属性会很好。每次添加迁移时不必记住哪些列需要什么;必须对生成的文件进行后期编辑,然后针对该更改的文件正常运行更新数据库。我想知道是否有可能覆盖这种不明智的行为……我不敢相信没有人对此有所改进。当然,我不是唯一一个对默认 AspNet 身份模型感到沮丧的人... LockoutEnabled、EmailConfirmed、AccessFailedCount。所有硬编码,所有问题
  • 这似乎不适用于 MySQL-EF。 'defaultValue' 没有设置值,并且 'defaultValueSql' 会创建一个异常(“blob 文本几何或 json 列不能有默认值”)......剩下的唯一解决方法是使用原始 SQL。 :(
  • 对于那些像我一样需要枚举默认值的人: AddColumn("dbo.report", "newEnumProperty", c => c.Int(nullable: false, defaultValue: 0)); //使用整数设置默认枚举值
  • 引用@Efrain,使用 EF Core 5 和 MySQL 我得到了空字段。不应用默认值。
  • 如何添加其他列的默认值,例如:我希望新的属性默认值为report.OldProperty?
【解决方案2】:

希望它可以帮助某人。将之前答案中的所有内容放在一起(使用布尔属性的示例)

1) 向实体添加新属性。

/// <summary>
/// Determines if user is enabled or not. Default value is true
/// </summary>
public bool IsEnabled { get; set; }

2) 运行以下命令以在迁移中添加新更改。

add-migration addIsEnabledColumn

3) 通过上述命令创建一个迁移文件,打开该文件。

4) 设置默认值。

public override void Up()
{
        AddColumn(
            "dbo.AspNetUsers", 
            "IsEnabled", 
            c => c.Boolean(
                nullable: false, 
                defaultValue: true
            )
        );
}

【讨论】:

  • 5) 在第 4 步之后运行 Update-Database 以使用更改更新实际数据库。添加这一点只是为了新手。
  • 是否可以让默认值成为其他字段的函数?
【解决方案3】:

您必须更改迁移脚本中添加属性/列的行,如下所示:

AddColumn("dbo.reports", "newProperty", c => c.String(nullable: false, defaultValue: "test"));

【讨论】:

    【解决方案4】:

    我通过覆盖 SaveChanges 方法解决了这个问题。请参阅下面的解决方案。

    1. 解决方案说明

      i) 覆盖 DbContext 类中的 SaveChanges 方法。

      public override int SaveChanges()
      {
          return base.SaveChanges();
      }
      

      ii) 编写逻辑来设置默认值

      public override int SaveChanges()
      {
          //set default value for your property
          foreach (var entry in ChangeTracker.Entries().Where(entry => entry.Entity.GetType().GetProperty("YOUR_PROPERTY") != null))
          {
              if (entry.State == EntityState.Added)
              {
                  if (entry.Property("YOUR_PROPERTY").CurrentValue == null)
                      entry.Property("YOUR_PROPERTY").CurrentValue = YOUR_DEFAULT_VALUE;
              }
          }
      
          return base.SaveChanges();
      }
      
    2. 示例

      public override int SaveChanges()
      {
          //set default value for RegistedDate property
          foreach (var entry in ChangeTracker.Entries().Where(entry => entry.Entity.GetType().GetProperty("RegistedDate") != null))
          {
              if (entry.State == EntityState.Added)
              {
                  if ((DateTime)entry.Property("RegistedDate").CurrentValue == DateTime.MinValue)
                      entry.Property("RegistedDate").CurrentValue = DateTime.Now;
              }
          }
      
          //set default value for IsActive property
          foreach (var entry in ChangeTracker.Entries().Where(entry => entry.Entity.GetType().GetProperty("IsActive") != null))
          {
              if (entry.State == EntityState.Added)
              {
                  if(entry.Property("IsActive").CurrentValue == null)
                      entry.Property("IsActive").CurrentValue = false;
              }
          }
      
          return base.SaveChanges();
      }
      

    【讨论】:

      【解决方案5】:

      我发现仅对实体属性使用 Auto-Property Initializer 就足以完成工作。

      例如:

      public class Thing {
          public bool IsBigThing { get; set; } = false;
      }
      

      【讨论】:

      • 问题是它实际上并没有在数据库中设置默认值。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-08
      • 2018-11-23
      • 2023-01-01
      相关资源
      最近更新 更多