J'ai un modèle dans mon projet comme ci-dessous:
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; }
}
La migration est comme ci-dessous
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());
}
lorsque j'utilise Update-Database, l'erreur ci-dessous est générée:
L'objet 'DF__Receiv__FromN__25869641' dépend de la colonne 'FromNo'. ALTER TABLE ALTER COLUMN FromNo a échoué car un ou plusieurs objets accèdent à cette colonne.
Cette table n'a pas de clé étrangère ou quoi d'autre alors quel est le problème?
Vous avez une contrainte par défaut sur votre colonne. Vous devez d'abord supprimer la contrainte, puis modifier votre colonne.
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());
}
Vous devrez probablement supprimer également les contraintes par défaut sur vos autres colonnes.
Je viens de voir le commentaire d'Andrey (je sais - très tard) et il a raison. Une approche plus robuste consisterait donc à utiliser quelque chose comme:
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)
Je sais que cela n'aide probablement pas le PO, mais j'espère que cela aide toute autre personne qui rencontre ce problème.
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());
}
Ceci est un exemple pour changer une colonne existante en 'non nul' qui a déjà une contrainte de clé étrangère. Le nom de la colonne est "FKColumnName" dans la table "SubTable" et fait référence à la colonne "Id" dans la table "MainTable".
Script supérieur:
Une fois que la colonne est rendue "non nulle", l'index et la clé étrangère ont d'abord été supprimés, puis recréés.
Down script:
Ici, les étapes sont identiques, sauf que la colonne est de nouveau nullable.
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");
}
}
La meilleure façon est de résoudre le problème pour toujours.
Vous pouvez implémenter une classe de générateur SQL personnalisée dérivée de SqlServerMigrationSqlGenerator à partir de l'espace de noms System.Data.Entity.SqlServer:
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);
}
}
}
et définissez cette configuration:
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
SetSqlGenerator("System.Data.SqlClient", new FixedSqlServerMigrationSqlGenerator ());
}
...
}
J'avais ce problème avec une valeur par défaut de contrainte zéro sur une colonne entière.
Dans mon cas, je l'ai résolu en passant d'Entity Framework 6.1.x à EF 6.2.0.
Il y a un bogue connu dans EF avant 6.2 qui signifie que EF ne traite pas automatiquement ces types de contraintes lors de la modification des colonnes. Ce bug est décrit sur le repo officiel EF github ici , Bricelam décrit le problème comme:
Lors de l'ajout de colonnes NOT NULL, nous synthétisons une valeur par défaut pour toutes les lignes existantes. Il semble que notre logique consiste à supprimer les contraintes par défaut avant qu'ALTER COLUMN n'en tienne compte.
Le commit du correctif pour ce problème peut être trouvé ici .