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

91

J'ai ajouté l' [Required]annotation de données à l'un de mes modèles dans une application ASP.NET MVC . Après avoir créé une migration, l'exécution de la Update-Databasecommande entraîne l'erreur suivante:

Impossible d'insérer la valeur NULL dans la colonne 'Director', table 'MOVIES_cf7bad808fa94f89afa2e5dae1161e78.dbo.Movies'; La colonne n'autorise pas les valeurs nulles. UPDATE échoue. La déclaration a été terminée.

Cela est dû au fait que certains enregistrements ont NULL dans leurs Directorcolonnes. 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());
    }
}
Andriy Drozdyuk
la source

Réponses:

74

Si je me souviens bien, quelque chose comme ça 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, donc si la valeur requise est effectivement une chaîne, comme dans l'exemple John Doe, des guillemets simples sont requis autour de la valeur.

développeur web
la source
9
Je le pensais aussi, mais cela ne semble pas fonctionner pour les disques existants. Donc j'obtiens toujours une erreur.
Andriy Drozdyuk
@drozzy C'est peut-être un bogue, comme ici: EF 4.3.1 Migration Exception - AlterColumn defaultValueSql crée le même nom de contrainte par défaut pour différentes tables Vous pouvez mettre à jour les lignes avec IS NULLcheck par votre requête.
webdeveloper
Intéressant, mais je ne suis pas sûr de comprendre de quoi ils parlent. Cependant, s'il s'agit d'un bogue, alors oui, cela aurait du sens.
Andriy Drozdyuk
6
Je pense que cela devrait être: "'John Doe'"- vous devez utiliser des guillemets SQL.
Sean le
1
@webdeveloper, je ne pense pas que ce soit un bug, pourquoi AlterColumnmettre à jour les valeurs actuelles? Il s'agit d'une commande DDL (pas DML).
Anton
110

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"));
}

C'est parce que AlterColumnproduit DDL pour définir la valeur par défaut de la colonne sur une valeur spécifique dans la spécification de 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éfinissant la valeur par défaut et rendant la colonne NOT NULL) et chacune d'elles est valide individuellement, mais puisque vous effectuez les deux en même temps, vous pouvez vous attendre à ce que le système ' 'réalisez intelligemment votre intention et définissez toutes les NULLvaleurs sur la valeur par défaut, mais ce n'est pas ce qui est attendu tout le temps.

Supposons que vous ne définissiez que la valeur par défaut de la colonne et que vous ne la définissiez pas 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 bogue, et je ne veux pas qu'EF mette à jour mes données de la manière que je ne lui dis pas explicitement de le faire. Le développeur est responsable d'indiquer au système ce qu'il faut faire avec les données.

Iravanchi
la source
17
Pour les personnes qui trouvent cette réponse via google: je viens d'essayer cela dans EF6 et la déclaration de mise à jour ne semble plus nécessaire. Je suppose qu'ils considéraient cela comme un bogue après tout.
EPLKleijntjens
3
Je peux également en témoigner. Si vous avez besoin d'une valeur par défaut même pour un champ Nullable, changez-le simplement en Not-Nullable d'abord avec une valeur par défaut, puis remettez-le en Nullable. Très pratique lorsque vous avez ajouté un champ non nullable à une classe enfant :)
Wouter Schut
1
Spot sur l'explication. AlterColumn () modifie simplement la définition de la colonne. Cela n'affecte en rien les disques existants
Korayem
10
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());       
    }
}
Pushpendra
la source
2
Euh ... merci, mais en quoi est-ce différent de la réponse de @ webdeveloper?
Andriy Drozdyuk
1
il ne vous dit pas où vous devez ajouter le paramètre de valeur par défaut
Pushpendra
1
@Pushpendra, c'est drôle comment les développeurs ont tendance à oublier qu'il était une fois, ils ne savaient pas grand-chose. J'aime les réponses détaillées qui satisfont tous les niveaux. Excellent travail!
utileBee
5

Je ne sais pas si cette option était toujours là, mais juste rencontré un problème similaire, j'ai constaté que j'étais en mesure de définir la valeur par défaut sans exécuter de mises à jour manuelles en utilisant ce qui suit

defaultValueSql: "'NY'"

J'ai eu une erreur lorsque la valeur fournie était "NY"alors j'ai réalisé qu'ils attendaient une valeur SQL comme "GETDATE()"si j'ai essayé"'NY'" et cela a fait l'affaire

toute la ligne ressemble à ceci

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

Grâce à cette réponse , m'a mis sur la bonne voie

workabyte
la source
2

Depuis EF Core 2.1, vous pouvez utiliser MigrationBuilder.UpdateDatapour modifier les valeurs avant de modifier la colonne (plus propre que d'utiliser 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);
}
Antoine Robin
la source
1

J'ai trouvé que le simple fait d'utiliser l'initialiseur de propriété automatique sur la propriété de l'entité était suffisant pour faire le travail.

Par exemple:

public class Thing {
    public bool IsBigThing { get; set; } = false;
}
Velyo
la source
2
C'est une bonne réponse (m'a aidé), mais cela n'ajoute pas de valeur par défaut dans la base de données, cela définit la valeur dans le code.
chris31389
à droite, il n'a pas ajouté de valeur par défaut dans la base de données après les chnages de migration
Chetan Chaudhari
1

La plupart des autres réponses se concentrent sur la manière d'intervenir manuellement lorsque ces problèmes surviennent.

Après avoir généré la migration, effectuez l'une des modifications suivantes dans la migration:

  1. Modifiez la définition de colonne pour inclure une instruction defaultValue ou defaultSql:
    AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false, default: ""));

  2. Injectez une instruction SQL pour préremplir les colonnes existantes, avant AlterColumn:
    Sql("UPDATE dbo.Movies SET Director = '' WHERE Director IS NULL");

Gardez à l'esprit que les modifications manuelles appliquées à un script de migration seront écrasées si vous rééchafaudez la migration. Pour la première solution, il est assez facile d'étendre EF pour définir automatiquement une valeur par défaut sur un champ dans le cadre de la génération de migration.

REMARQUE: EF ne le fait pas automatiquement pour vous car l'implémentation de la valeur par défaut serait différente pour chaque fournisseur de SGBDR, mais aussi parce que les valeurs par défaut ont moins de signification dans un runtime EF pur car chaque insertion de ligne fournira la valeur actuelle pour chaque propriété, même si elle est nulle, la contrainte de valeur par défaut n'est donc jamais évaluée.
Cette instruction AlterColumn est la seule fois où la contrainte par défaut entre en jeu, je suppose que cela devient une priorité inférieure pour l'équipe qui a conçu l'implémentation de la migration SQL Server.

La solution suivante combine la notation d'attribut, les conventions de configuration du modèle et les annotations de colonne pour transmettre les métadonnées à un générateur de code de migration personnalisé. Les étapes 1 et 2 peuvent être remplacées par une notation fluide pour chaque champ affecté si vous n'utilisez pas la notation attributaire.
Il y a beaucoup de techniques en jeu ici, n'hésitez pas à en utiliser certaines ou toutes, j'espère qu'il y a de la valeur pour tout le monde ici


  1. Déclarez la valeur par défaut
    Créez ou réutilisez un attribut existant pour définir la valeur par défaut à utiliser, pour cet exemple, nous allons créer un nouvel attribut appelé DefaultValue qui hérite de ComponentModel.DefaultValueAttribute, car l'utilisation est intuitive et il y a une chance que existant les bases de code implémentent déjà cet attribut. Avec cette implémentation, vous devez uniquement utiliser cet attribut spécifique pour accéder à DefaultValueSql, ce qui est utile pour les dates et autres scénarios personnalisés.

    la mise en oeuvre

    [DefaultValue("Insert DefaultValue Here")]
    [Required]     /// <--- NEW
    public string Director { get; set; }
    
    // Example of default value sql
    [DefaultValue(DefaultValueSql: "GetDate()")]
    [Required]
    public string LastModified { get; set; }

    Attirer la définition

    namespace EFExtensions
    {
        /// <summary>
        /// Specifies the default value for a property but allows a custom SQL statement to be provided as well. <see cref="MiniTuber.Database.Conventions.DefaultValueConvention"/>
        /// </summary>
        public class DefaultValueAttribute : System.ComponentModel.DefaultValueAttribute
        {
            /// <summary>
            /// Specifies the default value for a property but allows a custom SQL statement to be provided as well. <see cref="MiniTuber.Database.Conventions.DefaultValueConvention"/>
            /// </summary>
            public DefaultValueAttribute() : base("")
            {
            }
    
            /// <i
            /// <summary>
            /// Optional SQL to use to specify the default value.
            /// </summary>
            public string DefaultSql { get; set; }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a Unicode character.
            /// </summary>
            /// <param name="value">
            /// A Unicode character that is the default value.
            /// </param>
            public DefaultValueAttribute(char value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using an 8-bit unsigned integer.
            /// </summary>
            /// <param name="value">
            /// An 8-bit unsigned integer that is the default value.
            /// </param>
            public DefaultValueAttribute(byte value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a 16-bit signed integer.
            /// </summary>
            /// <param name="value">
            /// A 16-bit signed integer that is the default value.
            /// </param>
            public DefaultValueAttribute(short value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a 32-bit signed integer.
            /// </summary>
            /// <param name="value">
            /// A 32-bit signed integer that is the default value.
            /// </param>
            public DefaultValueAttribute(int value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a 64-bit signed integer.
            /// </summary>
            /// <param name="value">
            /// A 64-bit signed integer that is the default value.
            /// </param>
            public DefaultValueAttribute(long value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a single-precision floating point number.
            /// </summary>
            /// <param name="value">
            /// A single-precision floating point number that is the default value.
            /// </param>
            public DefaultValueAttribute(float value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a double-precision floating point number.
            /// </summary>
            /// <param name="value">
            /// A double-precision floating point number that is the default value.
            /// </param>
            public DefaultValueAttribute(double value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a System.Boolean value.
            /// </summary>
            /// <param name="value">
            /// A System.Boolean that is the default value.
            /// </param>
            public DefaultValueAttribute(bool value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a System.String.
            /// </summary>
            /// <param name="value">
            /// A System.String that is the default value.
            /// </param>
            public DefaultValueAttribute(string value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class.
            /// </summary>
            /// <param name="value">
            /// An System.Object that represents the default value.
            /// </param>
            public DefaultValueAttribute(object value) : base(value) { }
    
            /// /// <inheritdoc/>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class, converting the specified value to the specified type, and using an invariant
            /// culture as the translation context.
            /// </summary>
            /// <param name="type">
            /// A System.Type that represents the type to convert the value to.
            /// </param>
            /// <param name="value">
            /// A System.String that can be converted to the type using the System.ComponentModel.TypeConverter
            /// for the type and the U.S. English culture.
            /// </param>
            public DefaultValueAttribute(Type type, string value) : base(value) { }
        }
    }
  2. Créez une convention pour injecter la valeur par défaut dans les annotations de colonne Les annotations de
    colonne sont utilisées pour transmettre des métadonnées personnalisées sur les colonnes au générateur de script de migration.
    L'utilisation d'une convention pour ce faire démontre la puissance de la notation d'attribut pour simplifier la façon dont les métadonnées fluides peuvent être définies et manipulées pour de nombreuses propriétés plutôt que de les spécifier individuellement pour chaque champ.

    namespace EFExtensions
    {
    
        /// <summary>
        /// Implement SQL Default Values from System.ComponentModel.DefaultValueAttribute
        /// </summary>
        public class DefaultValueConvention : Convention
        {
            /// <summary>
            /// Annotation Key to use for Default Values specified directly as an object
            /// </summary>
            public const string DirectValueAnnotationKey = "DefaultValue";
            /// <summary>
            /// Annotation Key to use for Default Values specified as SQL Strings
            /// </summary>
            public const string SqlValueAnnotationKey = "DefaultSql";
    
            /// <summary>
            /// Implement SQL Default Values from System.ComponentModel.DefaultValueAttribute
            /// </summary>
            public DefaultValueConvention()
            {
                // Implement SO Default Value Attributes first
                this.Properties()
                        .Where(x => x.HasAttribute<EFExtensions.DefaultValueAttribute>())
                        .Configure(c => c.HasColumnAnnotation(
                            c.GetAttribute<EFExtensions.DefaultValueAttribute>().GetDefaultValueAttributeKey(),
                            c.GetAttribute<EFExtensions.DefaultValueAttribute>().GetDefaultValueAttributeValue()
                            ));
    
                // Implement Component Model Default Value Attributes, but only if it is not the SO implementation
                this.Properties()
                        .Where(x => x.HasAttribute<System.ComponentModel.DefaultValueAttribute>())
                        .Where(x => !x.HasAttribute<MiniTuber.DataAnnotations.DefaultValueAttribute>())
                        .Configure(c => c.HasColumnAnnotation(
                            DefaultValueConvention.DirectValueAnnotationKey, 
                            c.GetAttribute<System.ComponentModel.DefaultValueAttribute>().Value
                            ));
            }
        }
    
        /// <summary>
        /// Extension Methods to simplify the logic for building column annotations for Default Value processing
        /// </summary>
        public static partial class PropertyInfoAttributeExtensions
        {
            /// <summary>
            /// Wrapper to simplify the lookup for a specific attribute on a property info.
            /// </summary>
            /// <typeparam name="T">Type of attribute to lookup</typeparam>
            /// <param name="self">PropertyInfo to inspect</param>
            /// <returns>True if an attribute of the requested type exists</returns>
            public static bool HasAttribute<T>(this PropertyInfo self) where T : Attribute
            {
                return self.GetCustomAttributes(false).OfType<T>().Any();
            }
    
            /// <summary>
            /// Wrapper to return the first attribute of the specified type
            /// </summary>
            /// <typeparam name="T">Type of attribute to return</typeparam>
            /// <param name="self">PropertyInfo to inspect</param>
            /// <returns>First attribuite that matches the requested type</returns>
            public static T GetAttribute<T>(this System.Data.Entity.ModelConfiguration.Configuration.ConventionPrimitivePropertyConfiguration self) where T : Attribute
            {
                return self.ClrPropertyInfo.GetCustomAttributes(false).OfType<T>().First();
            }
    
            /// <summary>
            /// Helper to select the correct DefaultValue annotation key based on the attribute values
            /// </summary>
            /// <param name="self"></param>
            /// <returns></returns>
            public static string GetDefaultValueAttributeKey(this EFExtensions.DefaultValueAttribute self)
            {
                return String.IsNullOrWhiteSpace(self.DefaultSql) ? DefaultValueConvention.DirectValueAnnotationKey : DefaultValueConvention.SqlValueAnnotationKey;
            }
    
            /// <summary>
            /// Helper to select the correct attribute property to send as a DefaultValue annotation value
            /// </summary>
            /// <param name="self"></param>
            /// <returns></returns>
            public static object GetDefaultValueAttributeValue(this EFExtensions.DefaultValueAttribute self)
            {
                return String.IsNullOrWhiteSpace(self.DefaultSql) ? self.Value : self.DefaultSql;
            }
        }
    
    }
  3. Ajouter la Convention au DbContext
    Il existe de nombreuses façons d'y parvenir , j'aime déclarer les conventions comme la première étape personnalisée dans ma logique ModelCreation, ce sera dans votre classe DbContext.

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        // Use our new DefaultValueConvention
        modelBuilder.Conventions.Add<EFExtensions.DefaultValueConvention>();
    
        // My personal favourites ;)
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
    
    }
  4. Remplacer le MigrationCodeGenerator
    Maintenant que ces annotations ont été appliquées aux définitions de colonne dans le modèle, nous devons modifier le générateur de script de migration pour utiliser ces annotations. Pour cela, nous hériterons de la System.Data.Entity.Migrations.Design.CSharpMigrationCodeGeneratorcar il nous suffit d'injecter un minimum de changement.
    Une fois que nous avons traité notre annotation personnalisée, nous devons la supprimer de la définition de colonne pour éviter qu'elle ne soit sérialisée dans la sortie finale.

    Consultez le code de la classe de base pour explorer d'autres utilisations: http://entityframework.codeplex.com/sourcecontrol/latest#src/EntityFramework/Migrations/Design/CSharpMigrationCodeGenerator.cs

    namespace EFExtensions
    {
        /// <summary>
        /// Implement DefaultValue constraint definition in Migration Scripts.
        /// </summary>
        /// <remarks>
        /// Original guide that provided inspiration for this https://romiller.com/2012/11/30/code-first-migrations-customizing-scaffolded-code/
        /// </remarks>
        public class CustomCodeGenerator : System.Data.Entity.Migrations.Design.CSharpMigrationCodeGenerator
        {
            /// <summary>
            /// Inject Default values from the DefaultValue attribute, if the DefaultValueConvention has been enabled.
            /// </summary>
            /// <seealso cref="DefaultValueConvention"/>
            /// <param name="column"></param>
            /// <param name="writer"></param>
            /// <param name="emitName"></param>
            protected override void Generate(ColumnModel column, IndentedTextWriter writer, bool emitName = false)
            {
                var annotations = column.Annotations?.ToList();
                if (annotations != null && annotations.Any())
                {
                    for (int index = 0; index < annotations.Count; index ++)
                    {
                        var annotation = annotations[index];
                        bool handled = true;
    
                        try
                        {
                            switch (annotation.Key)
                            {
                                case DefaultValueConvention.SqlValueAnnotationKey:
                                    if (annotation.Value?.NewValue != null)
                                    {
                                        column.DefaultValueSql = $"{annotation.Value.NewValue}";
                                    }
                                    break;
                                case DefaultValueConvention.DirectValueAnnotationKey:
                                    if (annotation.Value?.NewValue != null)
                                    {
                                        column.DefaultValue = Convert.ChangeType(annotation.Value.NewValue, column.ClrType);
                                    }
                                    break;
                                default:
                                    handled = false;
                                    break;
                            }
                        }
                        catch(Exception ex)
                        {
                            // re-throw with specific debug information
                            throw new ApplicationException($"Failed to Implement Column Annotation for column: {column.Name} with key: {annotation.Key} and new value: {annotation.Value.NewValue}", ex);
                        }
    
                        if(handled)
                        {
                            // remove the annotation, it has been applied
                            column.Annotations.Remove(annotation.Key);
                        }
                    }
                }
                base.Generate(column, writer, emitName);
            }
    
            /// <summary>
            /// Generates class summary comments and default attributes
            /// </summary>
            /// <param name="writer"> Text writer to add the generated code to. </param>
            /// <param name="designer"> A value indicating if this class is being generated for a code-behind file. </param>
            protected override void WriteClassAttributes(IndentedTextWriter writer, bool designer)
            {
                writer.WriteLine("/// <summary>");
                writer.WriteLine("/// Definition of the Migration: {0}", this.ClassName);
                writer.WriteLine("/// </summary>");
                writer.WriteLine("/// <remarks>");
                writer.WriteLine("/// Generated Time: {0}", DateTime.Now);
                writer.WriteLine("/// Generated By: {0}", Environment.UserName);
                writer.WriteLine("/// </remarks>");
                base.WriteClassAttributes(writer, designer);
            }
    
    
        }
    }
  5. Enregistrer le CustomCodeGenerator
    Dernière étape, dans le fichier de configuration DbMigration, nous devons spécifier le générateur de code à utiliser, recherchez Configuration.cs dans votre dossier de migration par défaut ...

    internal sealed class Configuration : DbMigrationsConfiguration<YourApplication.Database.Context>
    {
        public Configuration()
        {
            // I recommend that auto-migrations be disabled so that we control
            // the migrations explicitly 
            AutomaticMigrationsEnabled = false;
            CodeGenerator = new EFExtensions.CustomCodeGenerator();
        }
    
        protected override void Seed(YourApplication.Database.Context context)
        {
            //   Your custom seed logic here
        }
    }
Chris Schaller
la source
0

Pour une raison quelconque, que je n'étais pas en mesure de m'expliquer, la réponse approuvée ne fonctionne plus pour moi.

Cela a fonctionné sur une autre application, sur celle sur laquelle je travaille, ce n'est pas le cas.

Donc, une solution alternative, mais assez inefficace , serait de remplacer la méthode SaveChanges () comme indiqué ci-dessous. Cette méthode doit être sur la classe Context.

    public override int SaveChanges()
    {
        foreach (var entry in ChangeTracker.Entries().Where(entry => entry.Entity.GetType().GetProperty("ColumnName") != null))
        {
            if (entry.State == EntityState.Added)
            {
                entry.Property("ColumnName").CurrentValue = "DefaultValue";
            }
        }
Liviu Sosu
la source