我的项目中有一个模型如下:
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; }
}
迁移如下
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());
}
当我使用Update-Database时,会引发以下错误:
对象'DF__Receiv__FromN__25869641'取决于列 'FromNo'。 ALTER TABLE ALTER COLUMN FromNo失败,因为一个或多个 对象访问此列。
这个表没有外键或者还有什么问题?
答案 0 :(得分:72)
您的列上有默认约束。您需要先删除约束,然后更改列。
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());
}
您可能还必须删除其他列上的默认约束。
我刚看到安德烈的评论(我知道 - 很晚)他是对的。因此,更强大的方法是使用类似的东西:
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)
我知道这可能对OP没有帮助,但希望它可以帮助其他任何遇到此问题的人。
答案 1 :(得分:40)
static internal 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);
}
}
public override void Up()
{
this.DeleteDefaultContraint("dbo.Received", "FromNo");
AlterColumn("dbo.Received", "FromNo", c => c.String());
this.DeleteDefaultContraint("dbo.Received", "ToNo");
AlterColumn("dbo.Received", "ToNo", c => c.String());
this.DeleteDefaultContraint("dbo.Received", "TicketNo");
AlterColumn("dbo.Received", "TicketNo", c => c.String());
}
答案 2 :(得分:2)
这是将现有列更改为已经具有外键约束的“not null”的示例。
列的名称是表“SubTable”中的“FKColumnName”,它引用表“MainTable”中的“Id”列。
向上脚本:
在使列“不可为空”之后,首先删除索引和外键,然后重新创建。
向下脚本:
这里的步骤是相同的,只是列可以再次为空。
public partial class NameOfMigration : DbMigration
{
public override void Up()
{
DropForeignKey("dbo.SubTable", "FKColumnName", "dbo.MainTable");
DropIndex("dbo.SubTable", new[] { "FKColumnName" });
AlterColumn("dbo.SubTable", "FKColumnName", c => c.Int(nullable: false));
CreateIndex("dbo.SubTable", "FKColumnName");
AddForeignKey("dbo.SubTable", "FKColumnName", "dbo.MainTable", "Id");
}
public override void Down()
{
DropForeignKey("dbo.SubTable", "FKColumnName", "dbo.MainTable");
DropIndex("dbo.SubTable", new[] { "FKColumnName" });
AlterColumn("dbo.SubTable", "FKColumnName", c => c.Int(nullable: true));
CreateIndex("dbo.SubTable", "FKColumnName");
AddForeignKey("dbo.SubTable", "FKColumnName", "dbo.MainTable", "Id");
}
}
答案 3 :(得分:2)
更好的方法是永远解决问题。
您可以从System.Data.Entity.SqlServer命名空间实现从SqlServerMigrationSqlGenerator派生的自定义sql生成器类:
<section class="content">
<div class="row">
<!-- left column -->
<div class="col-md-6">
<!-- general form elements -->
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">Live Notification</h3>
{{ csrf_field() }}
</div>
<!-- /.box-header -->
<!-- form start -->
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script src="https://cdn.socket.io/socket.io-1.3.4.js"></script>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2" >
<div id="messages" ></div>
</div>
</div>
</div>
<script>
var socket = io.connect('http://localhost:8000');
socket.on('message', function (data) {
$("#messages").append("<p>" + data + "</p>");
});
</script>
</div>
</div>
</div>
</section>
并设置此配置:
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);
}
}
}
答案 4 :(得分:0)
我遇到了这个问题,整数列的默认值为零约束。
就我而言,我是通过从Entity Framework 6.1.x切换到EF 6.2.0来解决的。
6.2之前的EF中存在一个已知的错误,这意味着EF有时在更改列时不会自动处理这些类型的约束。该错误已在official EF github repo here中进行了描述,Bricelam将问题描述为:
添加NOT NULL列时,我们会为 现有行。似乎我们放弃默认约束的逻辑 在ALTER COLUMN之前没有考虑到这一点。
针对该问题can be found here的修复程序的提交。
答案 5 :(得分:-12)
如果你正在使用EF:
enable-migrations
add-migration initial
update-database
虽然,此解决方案将删除数据库中的所有当前项目。如果这不是你的意图,我会建议其他一个答案。