【发布时间】:2017-10-25 13:26:30
【问题描述】:
在删除列的迁移操作期间,如何生成 SQL 以在尝试删除列之前先检查该列的存在?
对于删除列操作实体框架目前生成这样的sql来删除列:
// Migration Operation:
DropColumn("dbo.Table", "Column");
// TSQL generated:
// Dependency management logic ...
ALTER TABLE [dbo].[Table] DROP COLUMN [Column]
如何更改 SQL 以首先检查列的存在:
// Migration Operation:
DropColumn("dbo.Table", "Column");
// TSQL desired:
IF EXISTS (SELECT * FROM sys.columns WHERE object_id = Object_id('dbo.Table') AND name = 'Column')
BEGIN
// Dependency management logic ...
ALTER TABLE [dbo].[Table] DROP COLUMN [Column]
END
我知道可以通过继承SqlServerMigrationSqlGenerator 来自定义迁移SQL。我这样做的尝试未能将默认的删除列逻辑包装在 IF 块中。请参见下面的示例:
public class CustomSqlServerMigrationSqlGenerator: SqlServerMigrationSqlGenerator
{
/// <summary>
/// Drop column only if it exists.
/// </summary>
protected override void Generate(System.Data.Entity.Migrations.Model.DropColumnOperation dropColumnOperation)
{
using (var writer = Writer())
{
writer.WriteLine(
"IF EXISTS (SELECT * FROM sys.columns WHERE object_id = Object_id('{0}') AND name = '{1}')",
dropColumnOperation.Table,
dropColumnOperation.Name);
writer.WriteLine("BEGIN");
Statement(writer);
}
// Default drop column logic
base.Generate(dropColumnOperation);
using (var writer = Writer())
{
writer.WriteLine("END");
Statement(writer);
}
}
}
来源:
【问题讨论】:
-
你通常不需要这样做,除非你的迁移搞砸了。 EF 会从上次迁移到当前迁移进行模式比较。如果这是 SQL Server 2016,则有一个新的 Drop If Exists statement,您可以将其编码到 Sql() 命令中。
-
@SteveGreene 它用于管理团队环境中的迁移。我们使用相同的迁移并在进行更改时重新构建它。用例是为了简化开发中的重新脚手架。一旦迁移达到生产状态,它就不会改变。问题集中在自定义sql迁移生成,而不是像Sql()这样手动添加迁移操作。当然还有其他方法可以在团队环境中管理迁移,但这些方法不符合我们的需求:msdn.microsoft.com/en-us/library/dn481501(v=vs.113).aspx。
-
在第二篇文章中使用
protected override void Generate(MigrationOperation migrationOperation)代替了同名的方法,但使用了DropColumnOperation参数:if (operation as DropColumnOperation) -
@SteveGreene 您是对的,但是当使用 Code First From Database 从现有数据库启动时,也很容易弄乱他的数据库或命名约定错误。 EF也远非完美。 EF 无法处理现有数据库的所有情况。
标签: entity-framework entity-framework-6 ef-code-first entity-framework-migrations sql-generation