Code First从int迁移到Guid主键问题

M K*_* II 5 entity-framework-6

我正在尝试将我的代码第一个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.
Run Code Online (Sandbox Code Playgroud)

我正在定义这样的列:

public partial class CustomField : BaseEntity
{

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid CustomFieldId { get; set; }
Run Code Online (Sandbox Code Playgroud)

在CustomFieldMapping.cs中映射它,如下所示:

public CustomFieldMapping()
{
    //Primary key
    HasKey(t => t.CustomFieldId);

    //Constraints 
    Property(t => t.CustomFieldId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Run Code Online (Sandbox Code Playgroud)

并且生成的迁移正在尝试执行此操作:

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");
Run Code Online (Sandbox Code Playgroud)

我希望它是一个顺序递增的Guid.我究竟做错了什么?

Dav*_*e B 7

为了解决这个问题,我在迁移类的Sql()方法Up()Down()方法中使用了一个方法.该Up()方法中的SQL命令字符串删除ID列上的主键约束,删除类型的ID列,int然后添加具有类型的新ID列Guid.该Down()方法执行相同的操作但删除Guid列并添加新int列.

我在Stack Overflow上找到了一些解决方案,通过在查询窗口中运行SQL命令来解决"更改列类型".解决你的评论:

我们只是试图保持一个干净/清晰的迁移路径来跟踪我们做什么,这对于SQL来说并不总是那么容易.

我在Up()Down()迁移方法中使用了SQL命令.对我来说,这个解决方案适用于我的项目.

这个答案底部的解决方案是从几个Stack Overflow问题/答案中构建的.仅针对代码跳到那个.以下是冗长的细节.

在迁移类中使用SQL命令

我找不到像AlterColumn()(DropColumn()仅)那样使用Entity Framework迁移方法的解决方案.

Sql()我没有在方法中混合使用迁移方法和命令,而是使用了迁移方法中字符串中的所有SQL命令Sql().使用所有SQL命令可以更轻松地在Visual Studio或SQL Server Management Studio的查询窗口中进行测试.

'Uchitha' 的答案给出了Sql()在所需迁移类中添加"方法"的开始步骤.

  1. 使用Add-Migration生成迁移类
  2. 使用类似于上面的代码更改类
  3. 使用Update-Database运行迁移

Sql()答案中的方法示例如下:

Sql("UPDATE dbo.YourTable SET Column1 = 'VALUE1' "); 
Run Code Online (Sandbox Code Playgroud)

更改列类型 - 通用步骤

我使用'JustAnotherUserYouMayKnow' 的答案来开始更改列类型的步骤.我没有明确地遵循这个,但它只提供了删除列并重新创建它的基本框架.

  1. 使用新类型添加新列
  2. 用于Sql()使用update语句从原始列接管数据
  3. 删除旧列
  4. 重命名新列

顺序GUID

来自'Icarus' 的答案提供了ALTER TABLE语句,用于newsequentialid()根据您的语句生成顺序GUID:

我希望它是一个顺序递增的Guid.

ALTER TABLE your_table
    ADD your_column UNIQUEIDENTIFIER DEFAULT newsequentialid() NOT null
Run Code Online (Sandbox Code Playgroud)

请注意'Icarus'在答案的评论部分中'Johan'的隐私问题:

如果隐私是一个问题,请不要使用newsequentialid().可以猜测下一个生成的GUID的值,因此可以访问与该GUID相关联的访问数据

改变主键

要更改的列是ID列,您已将其设置为主键.因此,在删除现有ID列之前,您需要使用另一个ALTER TABLESQL命令删除主键.

请参阅"darnir"中的选定答案,了解"如何使用SQL语法更改主键约束?"

ALTER TABLE <Table_Name>
DROP CONSTRAINT <constraint_name>

ALTER TABLE <Table_Name>
ADD CONSTRAINT <constraint_name> PRIMARY KEY (<Column1>,<Column2>)
Run Code Online (Sandbox Code Playgroud)

请参阅'Oleg'的注释,以确定这是否是一个因素:

PRIMARY KEY CONSTRAINT无法更改,您只能删除它并重新创建.对于大型数据集,它可能会导致运行时间过长,从而导致表不可用.

DROP CONSTRAINT执行上面的命令时遇到问题.结果窗格列出了自动生成的约束,即使我在ALTER TABLE ... ADD COLUMN命令中使用了特定的约束名称.请参阅此问题 "为什么SQL会继续创建DF约束?" 这个问题,如果你遇到类似的东西.

为了解决删除约束的问题,我在这个问题中使用了"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)
Run Code Online (Sandbox Code Playgroud)

'ScubaSteve的答案中'Seven'的评论.我添加了'if'条件,因为当没有找到约束时,EXEC会失败.

IF @ObjectName IS NOT NULL在EXEC命令之前添加此脚本幂等

最终的解决方案

确保在下面的代码中替换MyTableName,MyColumnNamedbo,分别为您的表名,列名(例如,将列名设置为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)        
    ");
}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

4559 次

最近记录:

7 年,5 月 前