目录
介绍
背景
怎么解决
如何自动化
在我们的OData服务项目中,我们有很多具有共同领域的模型。将这些字段更改为基类时,Migrations确实希望更新您的数据库。
介绍在重构我们的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属性设置为:
///
/// Gets or sets the modification date.
///
///
/// The modification date.
///
[Timestamp]
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public byte[] ModificationDate { get; set; }
在您创建的Add-Migration中,您必须执行以下操作。
您在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,则drop和add列都会创建。
不幸的是,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
{
///
///
///
///
internal class MyCodeGenerator : CSharpMigrationCodeGenerator
{
///
/// Generates the specified alter column operation.
///
/// The alter column operation.
/// The writer.
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();
下次添加新迁移时,此问题已为您解决。
https://www.codeproject.com/Tips/5316668/EF6-Migrations-and-TimeStamp-Bug-with-CodeFirst