由于默认值约束,代码优先迁移失败
本文关键字:迁移 失败 代码 默认值 约束 | 更新日期: 2023-09-27 18:37:02
更改实体上的 a 属性类型时出现问题,创建了默认约束,但 EF 在更改列时未将其删除,因此,更新数据库失败。
该实体以前具有 DateTime 属性。
public DateTime ImportDate { get; set; }
它的迁移包含在其Up()
方法
AddColumn("dbo.Table", "ImportDate", c => c.DateTime(nullable: false));
但是,它还创建了一个默认约束
ALTER TABLE [dbo].[Table] ADD DEFAULT ('1900-01-01T00:00:00.000') FOR [ImportDate]
导入日期正在更改为日期时间偏移量
public DateTimeOffset ImportDate { get; set; }
并且生成的迁移具有 AlterColumn
AlterColumn("dbo.Table", "ImportDate", c => c.DateTimeOffset(nullable: false, precision: 7));
但是,此操作将失败,因为存在默认约束。
我能想到的唯一方法是将Sql(...)
与 DROP 约束一起使用,但是,约束有一个看似随机的名称DF__Table__Import__5441852A
因此硬编码的 SQL 不会在任何地方都有效。
思潮?
您可以创建一个扩展并在生成的迁移中使用它:
internal static class MigrationExtensions
{
public static void DeleteDefaultContraint(this IDbMigration migration, string tableName, string colName, bool suppressTransaction = false)
{
var sql = new SqlOperation(String.Format(@"DECLARE @SQL varchar(1000)
SET @SQL='ALTER TABLE {0} DROP CONSTRAINT ['+(SELECT name
FROM sys.default_constraints
WHERE parent_object_id = object_id('{0}')
AND col_name(parent_object_id, parent_column_id) = '{1}')+']';
PRINT @SQL;
EXEC(@SQL);", tableName, colName)) { SuppressTransaction = suppressTransaction };
migration.AddOperation(sql);
}
}
并像这样使用
this.DeleteDefaultContraint("dbo.Table", "ImportDate");
来自这篇文章:在 LINQ 中分组
更好的方法是永远解决问题。
您可以从 System.Data.Entity.SqlServer 命名空间实现从 SqlServerMigrationSqlGenerator 派生的自定义 sql 生成器类:
using System.Data.Entity.Migrations.Model;
using System.Data.Entity.SqlServer;
namespace System.Data.Entity.Migrations.Sql{
internal class FixedSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator {
protected override void Generate(AlterColumnOperation alterColumnOperation){
ColumnModel column = alterColumnOperation.Column;
var sql = String.Format(@"DECLARE @ConstraintName varchar(1000);
DECLARE @sql varchar(1000);
SELECT @ConstraintName = name FROM sys.default_constraints
WHERE parent_object_id = object_id('{0}')
AND col_name(parent_object_id, parent_column_id) = '{1}';
IF(@ConstraintName is NOT Null)
BEGIN
set @sql='ALTER TABLE {0} DROP CONSTRAINT [' + @ConstraintName+ ']';
exec(@sql);
END", alterColumnOperation.Table, column.Name);
this.Statement(sql);
base.Generate(alterColumnOperation);
return;
}
protected override void Generate(DropColumnOperation dropColumnOperation){
var sql = String.Format(@"DECLARE @SQL varchar(1000)
SET @SQL='ALTER TABLE {0} DROP CONSTRAINT [' + (SELECT name
FROM sys.default_constraints
WHERE parent_object_id = object_id('{0}')
AND col_name(parent_object_id, parent_column_id) = '{1}') + ']';
PRINT @SQL;
EXEC(@SQL); ", dropColumnOperation.Table, dropColumnOperation.Name);
this.Statement(sql);
base.Generate(dropColumnOperation);
}
}
}
并设置此配置:
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
SetSqlGenerator("System.Data.SqlClient", new FixedSqlServerMigrationSqlGenerator ());
}
...
}