EF6 迁移和时间戳错误,使用 CodeFirst





5.00/5 (3投票s)
迁移不适用于 T-SQL 中 ALTER TABLE ALTER COLUMN 的规则
引言
在重构我们的 ASP.NET WEBAPI Odata 服务时,我们发现每个模型中返回四个字段。其中一个是 ModificationDate
属性,它是一个 TimeStamp
字段。因此,当从模型中删除这四个字段,并通过基类将它们添加到模型中时,迁移会做一些非常愚蠢的事情。它会为你的 TimeStamp
字段创建一个 AlterColumn
语句。当你从包管理器控制台运行 Update-Database 命令时,你会看到一个漂亮的错误
Cannot alter column 'ModificationDate' to be data type timestamp.
但是 Microsoft SQL Server 的文档 非常清楚。
ALTER COLUMN
指定要更改或修改的命名列。有关更多信息,请参阅 sp_dbcmptlevel (Transact-SQL)。
修改后的列不能是以下任何一种
-
具有时间戳数据类型的列。
这是迁移中的一个 BUG!
背景
基类中的 ModificationDate
属性的设置如下
/// <summary>
/// Gets or sets the modification date.
/// </summary>
/// <value>
/// The modification date.
/// </value>
[Timestamp]
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public byte[] ModificationDate { get; set; }
如何解决
在创建的 Add-Migration <YourPickedName>
中,你必须执行以下操作。
你在 Up()
方法中的行将是
AlterColumn("dbo.YourTable", "ModificationDate",
c => c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"));
你将其更改为
DropColumn("dbo.YourTable", "ModificationDate");
AddColumn("dbo.YourTable", "ModificationDate",
c => c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"));
因此,硬删除并重新创建是解决方案。
下一个问题是,我们必须为超过 300 个表更改它,因此我们在服务中创建了代码,在创建迁移时,如果我们将 ModificationDate
作为 fieldname
,则会创建删除和添加列。
不幸的是,System.Data.Entity.Core.Metadata.Edm.PrimitiveTypeKind
具有 Byte
,但没有可用的 TimeStamp
或 RowVersion
。否则,你可以通过其 DataType
(alterColumnOperation.Column.Type
) 来修复此问题。
如何自动化
在你的项目中,你有一个 Migrations 文件夹,你可以在其中添加一个类 MyCodeGenerator
using System.Data.Entity.Migrations.Design;
using System.Data.Entity.Migrations.Model;
using System.Data.Entity.Migrations.Utilities;
namespace MyHappyService.Migrations
{
/// <summary>
///
/// </summary>
/// <seealso cref="System.Data.Entity.Migrations.Design.CSharpMigrationCodeGenerator" />
internal class MyCodeGenerator : CSharpMigrationCodeGenerator
{
/// <summary>
/// Generates the specified alter column operation.
/// </summary>
/// <param name="alterColumnOperation">The alter column operation.</param>
/// <param name="writer">The writer.</param>
protected override void Generate
(AlterColumnOperation alterColumnOperation, IndentedTextWriter writer)
{
if (alterColumnOperation.Column.Name == "ModificationDate")
{
DropColumnOperation dropColumnOperation = new DropColumnOperation
(alterColumnOperation.Table, alterColumnOperation.Column.Name);
AddColumnOperation addColumnOperation = new AddColumnOperation
(alterColumnOperation.Table, alterColumnOperation.Column);
base.Generate(dropColumnOperation, writer);
base.Generate(addColumnOperation, writer);
}
else
base.Generate(alterColumnOperation, writer);
}
}
}
在你的 Configuration.cs 中,你在构造函数中添加
CodeGenerator = new MyCodeGenerator();
下次你添加新的迁移时,此问题将为你解决。
祝您编码愉快!
历史
- 2021年11月2日:Init v0.1:首次撰写此问题