entity-framework - Entity Framework 6 : Migration Drop column if exists

标签 entity-framework entity-framework-6 ef-code-first entity-framework-migrations sql-generation

在删除列的迁移操作期间,如何在尝试删除列之前先生成 SQL 以检查该列是否存在?

对于删除列操作, Entity Framework 当前生成这样的 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);
        }
    }
}

资料来源:
  • Entity Framework 6: How to override SQL generator?
  • Romiller on customizing code first migrations
  • EF 6 SqlServerMigrationSqlGenerator drop column logic
  • 最佳答案

    如果您已正确配置您的 CustomSqlServerMigrationSqlGenerator然后在执行 Update-Database 期间您应该遇到过此错误消息:

    System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near 'BEGIN'.
    
    问题是您已经构造并执行了 3 个部分语句,即对 Statement() 的调用。默认情况下,作为单个批处理操作执行,并且在语句中包含实际的 DropColumn 语句和 End 之前,您的批处理是无效的语法。
    由于基本实现不允许我们通过文本编写器(我们需要的方法标记为 protected )我们被迫做的是完全忽略基本实现:
    /// <summary>
    /// Drop column only if it exists.
    /// </summary>
    /// <remarks>This helps when we're stuffed up a previous migration or someone has already executed the drop in the DB direct.</remarks>
    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");
    
            // Base Implementation, increase the indentation
            writer.Indent++;
            writer.WriteLine("ALTER TABLE {0}", Quote(dropColumnOperation.Table));
            writer.WriteLine("DROP COLUMN {0}", Quote(dropColumnOperation.Name));
            writer.Indent--;
    
            writer.WriteLine("END");
    
            Statement(writer);
        }
    }
    
    如果您没有看到当前的错误,可能是 CustomSqlServerMigrationSqlGenerator未正确注册,请确保您已在 Configuration.cs 中的 Configuration 类的构造函数中设置它,例如:
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
        AutomaticMigrationDataLossAllowed = false;
        // Register the Customized SQL Generator to use
        this.SetSqlGenerator("System.Data.SqlClient", new CustomSqlServerMigrationSqlGenerator());
    }
    

    如果您需要调试这个过程,请按照advice in this post这与此场景类似,您可以在生成器类的构造函数中放置一个断点:
    public class CustomSqlServerMigrationSqlGenerator: SqlServerMigrationSqlGenerator
    {
        public CustomSqlServerMigrationSqlGenerator()
            : base()
        {
            if (!System.Diagnostics.Debugger.IsAttached)
                System.Diagnostics.Debugger.Launch();
        }
    
        ...
    }
    

    关于entity-framework - Entity Framework 6 : Migration Drop column if exists,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46933717/

    相关文章:

    c# - 为什么在使用 Entity Framework 时看不到 Local 属性?

    entity-framework - 如何更新 EF6 Code First 中的虚拟属性?

    mysql - 空间/全文/哈希索引和显式索引顺序 EF 的使用不正确

    entity-framework - Entity Framework : create one-to-one relation to itself

    c# - 保存枚举时值不正确

    entity-framework - OptimisticConcurrencyException-SQL 2008 R2而不是使用 Entity Framework 的插入触发器

    c# - Entity Framework - 只有 edmx,没有模板

    entity-framework - SQL Server 中的代码优先文件表

    c# - 为最小 int 值设置约束

    entity-framework - SQL 超时已过期。操作完成前超时时间已过或服务器未响应