为了解决这个问题我使用了Sql()
方法中的Up()
and Down()
迁移类的方法。 SQL命令字符串在Up()
方法删除 ID 列上的主键约束,删除类型的 ID 列int
然后添加一个新的 ID 列,其类型为Guid
. The Down()
方法做同样的事情但放弃Guid
列并添加一个新的int
column.
我在 Stack Overflow 上找到了一些解决方案,可以通过在查询窗口中运行 SQL 命令来解决“更改列类型”问题。针对您的评论:
我们只是想保持一个干净/清晰的迁移路径来跟踪
我们做了一些使用 SQL 并不总是容易的事情。
我在其中使用了 SQL 命令Up()
and Down()
迁移方法。对我来说,这个解决方案在我的项目中效果很好。
本答案底部的解决方案是由几个 Stack Overflow 问题/答案构建的。跳到此处仅查看代码。这是冗长的细节。
在迁移类中使用 SQL 命令
我找不到使用实体框架迁移方法的解决方案,例如AlterColumn()
and DropColumn()
ONLY.
而不是在迁移方法和命令中混合使用Sql()
方法中,我使用了字符串中的所有 SQL 命令Sql()
迁移方法。使用所有 SQL 命令可以更轻松地在 Visual Studio 或 SQL Server Management Studio 的查询窗口中进行测试。
The answer https://stackoverflow.com/questions/26535189/entity-framework-execute-sql-before-migrations由“Uchitha”给出了添加的起始步骤Sql()
“所需迁移类中的方法。”
- 使用 Add-Migration 生成迁移类
- 使用与上面类似的代码更改类
- 使用更新数据库运行迁移
The Sql()
答案中的方法示例如下所示:
Sql("UPDATE dbo.YourTable SET Column1 = 'VALUE1' ");
更改列类型 - 一般步骤
我用的是answer https://stackoverflow.com/questions/14837168/ef5-code-first-changing-a-column-type-with-migrations通过“JustAnotherUserYouMayKnow”开始更改列类型的步骤。我没有明确遵循这一点,但它只提供了删除列并重新创建它的需要的基本框架。
- 使用您的新类型添加新列
- Use
Sql()
使用更新语句接管原始列中的数据
- 删除旧列
- 重命名新列
顺序 GUID
The answer https://stackoverflow.com/questions/11974939/adding-a-uniqueidentifier-column-and-adding-the-default-to-generate-new-guid来自“Icarus”的 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 命令。
查看所选的answer https://stackoverflow.com/questions/8761570/how-can-i-alter-a-primary-key-constraint-using-sql-syntax来自“darnir”的“如何使用 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
命令。看到这个question https://stackoverflow.com/questions/7663390/why-does-sql-keep-creating-a-df-constraint“为什么 SQL 不断创建 DF 约束?”和这个question https://stackoverflow.com/questions/19460912/the-object-df-is-dependent-on-column-changing-int-to-double如果你经历过类似的事情。
为了解决删除约束的问题,我使用了“ScubaSteve”的答案question https://stackoverflow.com/questions/1430456/how-to-drop-sql-default-constraint-without-knowing-its-name:“如何在不知道其名称的情况下删除 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 的回答”中“七”的评论。我添加了“if”条件,因为有时当未找到约束时 EXEC 会失败。
要使此脚本具有幂等性,请添加IF @ObjectName IS NOT NULL
在 EXEC 命令之前
最终的解决方案
确保更换MyTableName
, MyColumnName
, and 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)
");
}