用于更改列的数据类型的EF迁移

Poo*_*ani 49 c# entity-framework visual-studio ef-migrations entity-framework-5

我的项目中有一个模型如下:

public class Model 
{
    public int Id { get; set; }
    public long FromNo { get; set; }
    public long ToNo { get; set; }
    public string Content { get; set; }
    public long TicketNo { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

迁移如下

public override void Down()
{
    AlterColumn("dbo.Received", "FromNo", c => c.Long(nullable: false));
    AlterColumn("dbo.Received", "ToNo", c => c.Long(nullable: false));
    AlterColumn("dbo.Received", "TicketNo", c => c.Long(nullable: false));
}
public override void Up()
{
    AlterColumn("dbo.Received", "FromNo", c => c.String());
    AlterColumn("dbo.Received", "ToNo", c => c.String());
    AlterColumn("dbo.Received", "TicketNo", c => c.String());
}
Run Code Online (Sandbox Code Playgroud)

当我使用Update-Database时,会引发以下错误:

对象'DF__Receiv__FromN__25869641'依赖于列'FromNo'.ALTER TABLE ALTER COLUMN FromNo失败,因为一个或多个对象访问此列.

这个表没有外键或者其他什么,那么问题是什么?

Jam*_*ull 75

您的列上有默认约束.您需要先删除约束,然后更改列.

public override void Up()
{
    Sql("ALTER TABLE dbo.Received DROP CONSTRAINT DF_Receiv_FromN__25869641");
    AlterColumn("dbo.Received", "FromNo", c => c.String());
    AlterColumn("dbo.Received", "ToNo", c => c.String());
    AlterColumn("dbo.Received", "TicketNo", c => c.String());
}
Run Code Online (Sandbox Code Playgroud)

您可能还必须删除其他列上的默认约束.

我刚看到安德烈的评论(我知道 - 很晚),他是对的.所以更强大的方法是使用类似的东西:

 DECLARE @con nvarchar(128)
 SELECT @con = name
 FROM sys.default_constraints
 WHERE parent_object_id = object_id('dbo.Received')
 AND col_name(parent_object_id, parent_column_id) = 'FromNo';
 IF @con IS NOT NULL
     EXECUTE('ALTER TABLE [dbo].[Received] DROP CONSTRAINT ' + @con)
Run Code Online (Sandbox Code Playgroud)

我知道这可能对OP没有帮助,但希望它可以帮助其他任何遇到此问题的人.

  • 约束名称由SQL Server自动生成.虽然此代码将在开发环境中工作 - 但它不会在生产中,因为在不同的数据库中,约束名称将不同 (21认同)
  • @DaveGordon:你会把它放在`sql()`方法的调用中,如下所示:`Sql(@"DECLARE @con nvarchar(128)SELECT @con = name FROM sys.default_constraints WHERE parent_object_id = object_id('dbo .Received')AND col_name(parent_object_id,parent_column_id)='FromNo'; IF @con IS NOT NULL EXECUTE('ALTER TABLE [dbo].[Received] DROP CONSTRAINT'+ @con)");` (9认同)

小智 41

static internal class MigrationExtensions
{
    public static void DeleteDefaultConstraint(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);
    }
}

public override void Up()
{
    this.DeleteDefaultConstraint("dbo.Received", "FromNo");
    AlterColumn("dbo.Received", "FromNo", c => c.String());
    this.DeleteDefaultConstraint("dbo.Received", "ToNo");
    AlterColumn("dbo.Received", "ToNo", c => c.String());
    this.DeleteDefaultConstraint("dbo.Received", "TicketNo");
    AlterColumn("dbo.Received", "TicketNo", c => c.String());
}
Run Code Online (Sandbox Code Playgroud)

  • 这完美,比接受的答案更好,因为它的动态而不是硬编码. (3认同)
  • @Kleky我遇到了这个问题并通过将MigrationExtensions类放在迁移的不同文件中来解决它(在我的例子中是Migrations文件夹中的MigrationExtensions.cs). (2认同)