Entity Framework迁移中必填字段的默认值?

And*_*yuk 87 c# asp.net-mvc entity-framework ef-code-first

我已经将[Required]数据注释添加到ASP.NET MVC应用程序中的一个模型中.创建迁移后,运行该Update-Database命令会导致以下错误:

无法将值NULL插入列'Director',表'MOVIES_cf7bad808fa94f89afa2e5dae1161e78.dbo.Movies'; 列不允许空值.更新失败.该语句已终止.

这是因为某些记录的Director列中包含NULL .如何自动将这些值更改为默认值(例如"John Doe")导演?

这是我的模型:

  public class Movie
    {
        public int ID { get; set; }
        [Required]
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Required]
        public string Genre { get; set; }

        [Range(1,100)]
        [DataType(DataType.Currency)]
        public decimal Price { get; set; }

        [StringLength(5)]
        public string Rating { get; set; }

        [Required]     /// <--- NEW
        public string Director { get; set; }
    }
Run Code Online (Sandbox Code Playgroud)

这是我最近的迁移:

public partial class AddDataAnnotationsMig : DbMigration
{
    public override void Up()
    {
        AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false));
        AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false));
        AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5));
        AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false));
    }

    public override void Down()
    {
        AlterColumn("dbo.Movies", "Director", c => c.String());
        AlterColumn("dbo.Movies", "Rating", c => c.String());
        AlterColumn("dbo.Movies", "Genre", c => c.String());
        AlterColumn("dbo.Movies", "Title", c => c.String());
    }
}
Run Code Online (Sandbox Code Playgroud)

Ira*_*chi 105

除了@webdeveloper和@Pushpendra的答案之外,您还需要手动向迁移添加更新以更新现有行.例如:

public override void Up()
{
    Sql("UPDATE [dbo].[Movies] SET Title = 'No Title' WHERE Title IS NULL");
    AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false,defaultValue:"MyTitle"));
}
Run Code Online (Sandbox Code Playgroud)

这是因为AlterColumn生成DDL以将列的默认值设置为表规范中的某个特定值.DDL不会影响数据库中的现有行.

你实际上是在同一时间进行两次更改(设置默认值并使列为NOT NULL),并且每个更改都是单独有效的,但由于你是同时制作两个,所以你可以期望系统'智能地'实现你的意图并将所有NULL值设置为默认值,但这不是所期望的.

假设您只设置列的默认值,而不是使其为NOT NULL.您显然不希望使用您提供的默认值更新所有NULL记录.

因此,在我看来,这不是一个错误,我不希望EF以我没有明确告诉它的方式更新我的数据.开发人员负责指示系统如何处理数据.

  • 对于通过谷歌找到这个答案的人:我只是在EF6中试过这个,并且似乎没有必要更新语句(不再).我猜他们毕竟认为这是一个错误. (16认同)
  • 我也可以担保.如果即使对于可空字段也需要默认值,只需使用默认值将其更改为不可为空,然后将其更改为可为空.当你向子类添加一个不可为空的字段时非常方便:) (3认同)

web*_*per 71

如果我没记错的话,这样的事情应该有效:

AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false, defaultValueSql: "John Doe"));
Run Code Online (Sandbox Code Playgroud)

  • 我也这么认为,但这对现有记录来说似乎不起作用.所以我仍然得到一个错误. (8认同)
  • 我认为它应该是:`''John Doe'"` - 你需要使用SQL引号. (6认同)

小智 9

public partial class AddDataAnnotationsMig : DbMigration
{
    public override void Up()
    {
        AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false,defaultValue:"MyTitle"));
        AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false,defaultValue:"Genre"));
        AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5));
        AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false,defaultValue:"Director"));

    }

    public override void Down()
    {       
        AlterColumn("dbo.Movies", "Director", c => c.String());
        AlterColumn("dbo.Movies", "Rating", c => c.String());
        AlterColumn("dbo.Movies", "Genre", c => c.String());
        AlterColumn("dbo.Movies", "Title", c => c.String());       
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 嗯...谢谢,但与@ webdeveloper的答案有何不同? (2认同)

wor*_*yte 5

不确定这个选项是否总是存在但只是遇到了类似的问题,发现我能够设置默认值而不使用以下运行任何手动更新

defaultValueSql: "'NY'"

我提供的值是一个错误,"NY"然后我意识到他们正在期待一个SQL值,"GETDATE()"所以我试过"'NY'",这就是诀窍

整条线看起来像这样

AddColumn("TABLE_NAME", "State", c => c.String(maxLength: 2, nullable: false, defaultValueSql: "'NY'"));

多亏了这个答案,让我走上正轨


Ant*_*bin 5

Since EF Core 2.1, you can use MigrationBuilder.UpdateData to change values before altering the column (cleaner than using raw SQL):

protected override void Up(MigrationBuilder migrationBuilder)
{
    // Change existing NULL values to NOT NULL values
    migrationBuilder.UpdateData(
        table: tableName,
        column: columnName,
        value: valueInsteadOfNull,
        keyColumn: columnName,
        keyValue: null);

    // Change column type to NOT NULL
    migrationBuilder.AlterColumn<ColumnType>(
        table: tableName,
        name: columnName,
        nullable: false,
        oldClrType: typeof(ColumnType),
        oldNullable: true);
}
Run Code Online (Sandbox Code Playgroud)