Han*_*onn 6 entity-framework sql-generation ef-code-first entity-framework-6 entity-framework-migrations
在删除列的迁移操作期间,如何在尝试删除列之前先生成 SQL 以检查该列是否存在?
对于删除列操作,实体框架当前生成这样的 sql 来删除列:
// Migration Operation:
DropColumn("dbo.Table", "Column");
// TSQL generated:
// Dependency management logic ...
ALTER TABLE [dbo].[Table] DROP COLUMN [Column]
Run Code Online (Sandbox Code Playgroud)
如何更改 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
Run Code Online (Sandbox Code Playgroud)
我知道可以通过继承自SqlServerMigrationSqlGenerator. 我这样做的尝试未能将默认放置列逻辑包装在一个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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
资料来源:
如果您在执行过程中正确配置了CustomSqlServerMigrationSqlGeneratorthen,Update-Database您应该会遇到以下错误消息:
System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near 'BEGIN'.
Run Code Online (Sandbox Code Playgroud)
问题是您已经构造并执行了 3 个部分语句,默认情况下对 的调用作为单个批处理操作执行,并且在语句中包含实际的DropColumn语句和EndStatement()之前,您的批处理不是有效的语法。
由于基本实现不允许我们通过文本编写器(我们需要的方法被标记为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);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您没有看到当前错误,可能CustomSqlServerMigrationSqlGenerator是未正确注册,请确保您已在 Configuration.cs 中的 Configuration 类的构造函数中设置它,例如:
public Configuration()
{
AutomaticMigrationsEnabled = false;
AutomaticMigrationDataLossAllowed = false;
// Register the Customized SQL Generator to use
this.SetSqlGenerator("System.Data.SqlClient", new CustomSqlServerMigrationSqlGenerator());
}
Run Code Online (Sandbox Code Playgroud)
如果您需要调试此过程,请按照这篇文章中的建议进行操作,该文章的场景与此类似,您可以在生成器类的构造函数中放置一个断点:
public class CustomSqlServerMigrationSqlGenerator: SqlServerMigrationSqlGenerator
{
public CustomSqlServerMigrationSqlGenerator()
: base()
{
if (!System.Diagnostics.Debugger.IsAttached)
System.Diagnostics.Debugger.Launch();
}
...
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4100 次 |
| 最近记录: |