94 votes

Valeur par défaut pour les champs obligatoires dans les migrations Entity Framework ?

J'ai ajouté le [Required] de données à l'un de mes modèles dans un fichier Application ASP.NET MVC . Après avoir créé une migration, exécutez le Update-Database entraîne l'erreur suivante :

Impossible d'insérer la valeur NULL dans la colonne 'Director' de la table MOVIES_cf7bad808fa94f89afa2e5dae1161e78.dbo.Movies' ; la colonne n'autorise pas les nuls. n'autorise pas les valeurs nulles. L'UPDATE échoue. L'instruction a été interrompue.

Ceci est dû au fait que certains enregistrements ont NULL dans leur Director colonnes. Comment puis-je changer automatiquement ces valeurs en un directeur par défaut (disons "John Doe") ?

Voici mon modèle :

  public class Movie
    {
        public int ID { get; set; }
        [Required]
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Required]
        public string Genre { get; set; }

        [Range(1,100)]
        [DataType(DataType.Currency)]
        public decimal Price { get; set; }

        [StringLength(5)]
        public string Rating { get; set; }

        [Required]     /// <--- NEW
        public string Director { get; set; }
    }

et voici ma dernière migration :

public partial class AddDataAnnotationsMig : DbMigration
{
    public override void Up()
    {
        AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false));
        AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false));
        AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5));
        AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false));
    }

    public override void Down()
    {
        AlterColumn("dbo.Movies", "Director", c => c.String());
        AlterColumn("dbo.Movies", "Rating", c => c.String());
        AlterColumn("dbo.Movies", "Genre", c => c.String());
        AlterColumn("dbo.Movies", "Title", c => c.String());
    }
}

111voto

Iravanchi Points 1264

En plus de la réponse de @webdeveloper et @Pushpendra, vous devez ajouter manuellement des mises à jour à votre migration pour mettre à jour les lignes existantes. Par exemple :

public override void Up()
{
    Sql("UPDATE [dbo].[Movies] SET Title = 'No Title' WHERE Title IS NULL");
    AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false,defaultValue:"MyTitle"));
}

Cela s'explique par le fait que AlterColumn produit le DDL pour définir la valeur par défaut de la colonne à une valeur spécifique dans la spécification de la table. Le DDL n'affecte pas les lignes existantes dans la base de données.

Vous effectuez en fait deux modifications en même temps (définir la valeur par défaut et rendre la colonne NOT NULL) et chacune d'entre elles est valable individuellement, mais puisque vous effectuez les deux en même temps, vous pouvez vous attendre à ce que le système réalise "intelligemment" votre intention et définisse tous les paramètres de la colonne NOT NULL. NULL à la valeur par défaut, mais ce n'est pas toujours ce que l'on attend.

Supposons que vous définissiez uniquement la valeur par défaut de la colonne, sans la rendre NOT NULL. Vous ne vous attendez évidemment pas à ce que tous les enregistrements NULL soient mis à jour avec la valeur par défaut que vous fournissez.

Donc, à mon avis, ce n'est pas un bug, et je ne veux pas qu'EF mette à jour mes données d'une manière que je ne lui demande pas explicitement. Le développeur est responsable d'indiquer au système ce qu'il doit faire avec les données.

77voto

webdeveloper Points 8205

Si je me souviens bien, quelque chose comme ceci devrait fonctionner :

AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false, defaultValueSql: "'John Doe'"));

Remarque : la valeur du paramètre defaultValueSql est traitée comme une instruction SQL verbatim. Par conséquent, si la valeur requise est effectivement une chaîne de caractères, comme dans l'exemple de John Doe, des guillemets simples sont nécessaires autour de la valeur.

11voto

Pushpendra Points 468
public partial class AddDataAnnotationsMig : DbMigration
{
    public override void Up()
    {
        AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false,defaultValue:"MyTitle"));
        AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false,defaultValue:"Genre"));
        AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5));
        AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false,defaultValue:"Director"));

    }

    public override void Down()
    {       
        AlterColumn("dbo.Movies", "Director", c => c.String());
        AlterColumn("dbo.Movies", "Rating", c => c.String());
        AlterColumn("dbo.Movies", "Genre", c => c.String());
        AlterColumn("dbo.Movies", "Title", c => c.String());       
    }
}

5voto

workabyte Points 779

Je ne sais pas si cette option a toujours existé, mais je viens de rencontrer un problème similaire. J'ai découvert que je pouvais définir la valeur par défaut sans exécuter de mise à jour manuelle en utilisant les éléments suivants

defaultValueSql: "'NY'"

J'ai obtenu une erreur lorsque la valeur fournie était "NY" puis j'ai réalisé qu'ils attendaient une valeur SQL du type "GETDATE()" J'ai donc essayé "'NY'" et cela a fait l'affaire

la ligne entière ressemble à ceci

AddColumn("TABLE_NAME", "State", c => c.String(maxLength: 2, nullable: false, defaultValueSql: "'NY'"));

Merci à cette réponse m'a mis sur la bonne voie

5voto

Antoine Robin Points 78

Depuis EF Core 2.1, vous pouvez utiliser MigrationBuilder.UpdateData pour changer les valeurs avant de modifier la colonne (plus propre que l'utilisation du SQL brut) :

protected override void Up(MigrationBuilder migrationBuilder)
{
    // Change existing NULL values to NOT NULL values
    migrationBuilder.UpdateData(
        table: tableName,
        column: columnName,
        value: valueInsteadOfNull,
        keyColumn: columnName,
        keyValue: null);

    // Change column type to NOT NULL
    migrationBuilder.AlterColumn<ColumnType>(
        table: tableName,
        name: columnName,
        nullable: false,
        oldClrType: typeof(ColumnType),
        oldNullable: true);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X