问题描述
我们正在尝试使用Fluent API在带有EF Core 3.1的SQL Server上生成不可为空的rowversion列:
public class Person
{
public int Id { get; set; }
public byte[] Timestamp { get; set; }
}
public class PersonEntityConfiguration : IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
builder.HasKey(p => p.Id);
builder.Property(p => p.Timestamp)
.IsRowVersion()
.IsRequired();
}
}
当整个表是新表时,此方法工作正常:
public partial class PersonMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Persons",columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:Identity","1,1"),Timestamp = table.Column<byte[]>(rowVersion: true,nullable: false)
},constraints: table =>
{
table.PrimaryKey("PK_Persons",x => x.Id);
});
}
}
但是,有时我们需要将rowversion添加到现有表中。在这种情况下,EF Core会生成无效的迁移:
public partial class PersonTimestampMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<byte[]>(
name: "Timestamp",table: "Persons",rowVersion: true,nullable: false,defaultValue: new byte[] { });
}
}
上面生成的默认值在应用于数据库时将导致异常:
执行DbCommand失败(1ms)[Parameters = [],CommandType ='Text',CommandTimeout = '30']
ALTER TABLE [人员]添加[时间戳]行版本非NULL默认值0x;
Microsoft.Data.SqlClient.SqlException(0x80131904):无法在数据类型为timestamp的列上创建默认值。表“人员”,列“时间戳”。
无法创建约束或索引。查看先前的错误。
这是EF Core中的已知错误吗?可以通过从迁移中手动删除defaultValue: new byte[] { }
来解决此问题,但是有什么方法可以抑制使用Fluent API生成默认值?
解决方法
这是EF Core中的已知错误吗?
这肯定是错误/缺陷,但可能未知,因为即使在最新的EF Core 5.0预览版中,它也确实在发生。还是已知的,但是优先级较低(对于他们而言)-您必须检查EF Core Issue Tracker。
尝试显式添加.HasDefaultValue(null)
和.HasDefaultValueSql(null)
-没有帮助,因此唯一的选择是从迁移中手动删除defaultValue: new byte[] { }
。这样做的好处是,即使表具有现有记录,这样做也可以正常工作,并且可以成功创建和填充列(这就是EF Core通常为新的必需列添加此类defaultValue
参数的原因,但是如我们所见,不应该对ROWVERSION
这样做)。