我正在尝试将我的代码第一个ID列从“int”更改为“Guid”,并且在尝试运行迁移时,我收到消息:
Identity column 'CustomFieldId' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, and constrained to be nonnullable.
我正在定义这样的列:
public partial class CustomField : BaseEntity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid CustomFieldId { get; set; }
在CustomFieldMapping.cs中映射它,如下所示:
public CustomFieldMapping()
{
//Primary key
HasKey(t => t.CustomFieldId);
//Constraints
Property(t => t.CustomFieldId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
并且生成的迁移正在尝试执行此操作:
public override void Up()
{
DropForeignKey("dbo.CustomField", "CustomFormId", "dbo.CustomForm");
DropForeignKey("dbo.CustomData", "CustomFieldId", "dbo.CustomField");
DropForeignKey("dbo.CustomForm", "ParentFormId", "dbo.CustomForm");
DropIndex("dbo.CustomField", new[] { "CustomFormId" });
DropIndex("dbo.CustomForm", new[] { "ParentFormId" });
DropIndex("dbo.CustomData", new[] { "CustomFieldId" });
DropPrimaryKey("dbo.CustomField");
DropPrimaryKey("dbo.CustomForm");
AlterColumn("dbo.CustomField", "CustomFieldId", c => c.Guid(nullable: false));
AlterColumn("dbo.CustomField", "SortOrder", c => c.Int(nullable: false));
AlterColumn("dbo.CustomForm", "CustomFormId", c => c.Guid(nullable: false));
AlterColumn("dbo.CustomForm", "ParentFormId", c => c.Guid());
AddPrimaryKey("dbo.CustomField", "CustomFieldId");
AddPrimaryKey("dbo.CustomForm", "CustomFormId");
CreateIndex("dbo.CustomField", "CustomForm_CustomFormId");
CreateIndex("dbo.CustomForm", "ParentFormId");
CreateIndex("dbo.CustomData", "CustomField_CustomFieldId");
AddForeignKey("dbo.CustomField", "CustomForm_CustomFormId", "dbo.CustomForm", "CustomFormId");
AddForeignKey("dbo.CustomData", "CustomField_CustomFieldId", "dbo.CustomField", "CustomFieldId");
AddForeignKey("dbo.CustomForm", "ParentFormId", "dbo.CustomForm", "CustomFormId");
我希望它是一个顺序递增的Guid。我做错了什么?
答案 0 :(得分:7)
要解决此问题,我在迁移类的Sql()
和Up()
方法中使用了Down()
方法。 Up()
方法中的SQL命令字符串删除ID列上的主键约束,删除类型为int
的ID列,然后添加类型为Guid
的新ID列。 Down()
方法执行相同操作,但会删除Guid
列并添加新的int
列。
我在Stack Overflow上找到了一些解决方案,它通过在查询窗口中运行SQL命令来解析“更改列类型”。为了解决你的评论:
我们只是想保持一个干净/清晰的迁移路径来追踪 我们用SQL做了一些并不容易的事情。
我在Up()
和Down()
迁移方法中使用了SQL命令。对我来说,这个解决方案在我的项目中运作良好。
这个答案底部的解决方案是从几个Stack Overflow问题/答案中构建的。仅针对代码跳到那个。以下是冗长的细节。
我找不到仅使用AlterColumn()
和DropColumn()
等实体框架迁移方法的解决方案。
我没有在Sql()
方法中混合使用迁移方法和命令,而是使用了Sql()
迁移方法中字符串中的所有SQL命令。使用所有SQL命令可以更轻松地在Visual Studio或SQL Server Management Studio的查询窗口中进行测试。
'Uchitha'的answer给出了在所需迁移类中添加Sql()
“方法的开始步骤。”
答案中的Sql()
方法示例如下:
Sql("UPDATE dbo.YourTable SET Column1 = 'VALUE1' ");
我使用'{3}}'JustAnotherUserYouMayKnow'来开始更改列类型的步骤。我没有明确地遵循这一点,但它只提供了删除列并重新创建它的基本框架。
Sql()
使用更新语句接管原始列中的数据来自'Icarus'的answer提供了ALTER TABLE语句,使用newsequentialid()
根据您的语句生成顺序GUID:
我希望它是一个顺序递增的Guid。
ALTER TABLE your_table
ADD your_column UNIQUEIDENTIFIER DEFAULT newsequentialid() NOT null
请注意'Icarus'在答案的评论部分中'Johan'的隐私问题:
如果担心隐私,请不要使用
newsequentialid()
。可以猜测下一个生成的GUID的值,因此可以访问与该GUID相关联的访问数据
要更改的列是ID列,您已将其设置为主键。因此,在删除现有ID列之前,您需要使用另一个ALTER TABLE
SQL命令删除主键。
请参阅“darnir”中的选定answer“我如何使用SQL语法更改主键约束?”
ALTER TABLE <Table_Name>
DROP CONSTRAINT <constraint_name>
ALTER TABLE <Table_Name>
ADD CONSTRAINT <constraint_name> PRIMARY KEY (<Column1>,<Column2>)
请参阅'Oleg'的说明,以确定这是否是一个因素:
PRIMARY KEY CONSTRAINT无法更改,您只能删除它并重新创建。对于大型数据集,它可能会导致运行时间较长,从而导致表不可用。
执行上面DROP CONSTRAINT
的命令时出现问题。结果窗格列出了自动生成的约束,即使我在ALTER TABLE ... ADD COLUMN
命令中使用了特定的约束名称。请参阅此answer“为什么SQL会继续创建DF约束?”如果您遇到类似的事情,请question。
要通过删除约束解决问题,我使用了来自此question的'ScubaSteve'的答案:“如何在不知道其名称的情况下删除SQL默认约束?”通过'Seven'添加注释,这里是SQL命令:
DECLARE @ObjectName NVARCHAR(100)
SELECT @ObjectName = OBJECT_NAME([default_object_id]) FROM SYS.COLUMNS
WHERE [object_id] = OBJECT_ID('[tableSchema].[tableName]') AND [name] = 'columnName';
IF @ObjectName IS NOT NULL EXEC('ALTER TABLE [tableSchema].[tableName] DROP CONSTRAINT ' + @ObjectName)
'ScubaSteve的答案中'Seven'的评论。我添加了'if'条件,因为当没有找到约束时,EXEC会失败。
要使此脚本具有幂等性,请在EXEC命令
之前添加IF @ObjectName IS NOT NULL
请务必将以下代码中的MyTableName
,MyColumnName
和dbo
替换为您的表名,列名(例如,将列名设置为Id
)和表架构分别。
public override void Up()
{
Sql(@"
DECLARE @ObjectName NVARCHAR(100)
SELECT @ObjectName = OBJECT_NAME([default_object_id]) FROM SYS.COLUMNS
WHERE [object_id] = OBJECT_ID('[dbo].[MyTableName]') AND [name] = 'MyColumnName';
IF @ObjectName IS NOT NULL EXEC('ALTER TABLE [dbo].[MyTableName] DROP CONSTRAINT ' + @ObjectName)
ALTER TABLE dbo.MyTableName DROP CONSTRAINT PK_MyTableName, COLUMN MyColumnName
ALTER TABLE dbo.MyTableName
ADD Id UNIQUEIDENTIFIER DEFAULT (newsequentialid()) NOT NULL
CONSTRAINT PK_MyTableName
PRIMARY KEY CLUSTERED ([MyColumnName])
");
}
public override void Down()
{
Sql(@"
DECLARE @ObjectName NVARCHAR(100)
SELECT @ObjectName = OBJECT_NAME([default_object_id]) FROM SYS.COLUMNS
WHERE [object_id] = OBJECT_ID('[dbo].[MyTableName]') AND [name] = 'MyColumnName';
IF @ObjectName IS NOT NULL EXEC('ALTER TABLE [dbo].[MyTableName] DROP CONSTRAINT ' + @ObjectName)
ALTER TABLE dbo.MyTableName DROP CONSTRAINT PK_MyTableName, COLUMN Id
ALTER TABLE MyTableName
ADD MyColumnName int IDENTITY(1, 1) NOT NULL
CONSTRAINT PK_MyTableName
PRIMARY KEY CLUSTERED ([MyColumnName] ASC)
");
}
答案 1 :(得分:2)
我找到了解决问题的简单方法。您只需删除列Guid
,然后将其添加回public override void Up()
{
DropForeignKey("dbo.CustomField", "CustomFormId", "dbo.CustomForm");
DropForeignKey("dbo.CustomData", "CustomFieldId", "dbo.CustomField");
DropForeignKey("dbo.CustomForm", "ParentFormId", "dbo.CustomForm");
DropIndex("dbo.CustomField", new[] { "CustomFormId" });
DropIndex("dbo.CustomForm", new[] { "ParentFormId" });
DropIndex("dbo.CustomData", new[] { "CustomFieldId" });
DropPrimaryKey("dbo.CustomField");
DropPrimaryKey("dbo.CustomForm");
DropColumn("dbo.CustomField", "CustomFieldId")
AddColumn("dbo.CustomField", "CustomFieldId", c => c.Guid(nullable: false));
AlterColumn("dbo.CustomField", "SortOrder", c => c.Int(nullable: false));
AlterColumn("dbo.CustomForm", "CustomFormId", c => c.Guid(nullable: false));
AlterColumn("dbo.CustomForm", "ParentFormId", c => c.Guid());
AddPrimaryKey("dbo.CustomField", "CustomFieldId");
AddPrimaryKey("dbo.CustomForm", "CustomFormId");
CreateIndex("dbo.CustomField", "CustomForm_CustomFormId");
CreateIndex("dbo.CustomForm", "ParentFormId");
CreateIndex("dbo.CustomData", "CustomField_CustomFieldId");
AddForeignKey("dbo.CustomField", "CustomForm_CustomFormId", "dbo.CustomForm", "CustomFormId");
AddForeignKey("dbo.CustomData", "CustomField_CustomFieldId", "dbo.CustomField", "CustomFieldId");
AddForeignKey("dbo.CustomForm", "ParentFormId", "dbo.CustomForm", "CustomFormId");
列。这样就不会有任何错误消息,迁移将通过:
build.sbt