Standardwert für Erforderliche Felder in Entity Framework-Migrationen?

91

Ich habe die [Required]Datenanmerkung einem meiner Modelle in einer ASP.NET MVC-Anwendung hinzugefügt . Nach dem Erstellen einer Migration führt das Ausführen des Update-DatabaseBefehls zu folgendem Fehler:

Der Wert NULL kann nicht in die Spalte 'Director', Tabelle 'MOVIES_cf7bad808fa94f89afa2e5dae1161e78.dbo.Movies' eingefügt werden. Spalte erlaubt keine Nullen. UPDATE schlägt fehl. Die Anweisung wurde beendet.

Dies liegt daran, dass einige Datensätze NULL in ihren DirectorSpalten haben. Wie kann ich diese Werte automatisch in einen Standarddirektor (z. B. "John Doe") ändern?

Hier ist mein Modell:

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

und hier ist meine letzte 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
quelle

Antworten:

74

Wenn ich mich richtig erinnere, sollte so etwas funktionieren:

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

Hinweis: Der Parameterwert defaultValueSql wird als wörtliche SQL-Anweisung behandelt. Wenn der erforderliche Wert also effektiv eine Zeichenfolge ist, wie im Beispiel von John Doe, sind einfache Anführungszeichen um den Wert erforderlich.

Web-Entwickler
quelle
9
Das habe ich auch gedacht, aber das scheint für vorhandene Datensätze nicht zu funktionieren. Also bekomme ich immer noch einen Fehler.
Andriy Drozdyuk
@drozzy Möglicherweise liegt ein Fehler vor, wie hier: EF 4.3.1 Migrationsausnahme - AlterColumn defaultValueSql erstellt denselben Standardbeschränkungsnamen für verschiedene Tabellen. Sie können Zeilen mit IS NULLPrüfung durch Ihre Abfrage aktualisieren .
Webentwickler
Interessant, aber ich bin nicht sicher, ob ich verstehe, wovon sie sprechen. Wenn dies jedoch ein Fehler ist, dann wäre dies sinnvoll.
Andriy Drozdyuk
6
Ich denke, es sollte sein: "'John Doe'"- Sie müssen SQL-Anführungszeichen verwenden.
Sean
1
@webdeveloper, ich glaube nicht, dass es ein Fehler ist, warum sollten AlterColumnaktuelle Werte aktualisiert werden? Es ist ein DDL-Befehl (kein DML-Befehl).
Anton
110

Zusätzlich zur Antwort von @webdeveloper und @Pushpendra müssen Sie Ihrer Migration manuell Aktualisierungen hinzufügen, um vorhandene Zeilen zu aktualisieren. Beispielsweise:

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

Dies liegt daran, dass AlterColumnDDL erzeugt wird, um den Standardwert der Spalte auf einen bestimmten Wert in der Tabellenspezifikation festzulegen. Die DDL wirkt sich nicht auf vorhandene Zeilen in der Datenbank aus.

Sie nehmen tatsächlich zwei Änderungen gleichzeitig vor (Festlegen der Standardeinstellung und Festlegen der Spalte NOT NULL), und jede davon ist einzeln gültig. Da Sie jedoch beide Änderungen gleichzeitig vornehmen, können Sie davon ausgehen, dass das System ' Verwirklichen Sie Ihre Absicht auf intelligente Weise und setzen Sie alle NULLWerte auf den Standardwert. Dies wird jedoch nicht immer erwartet.

Angenommen, Sie legen nur den Standardwert für die Spalte fest und machen ihn nicht auf NULL. Sie erwarten offensichtlich nicht, dass alle NULL-Datensätze mit dem von Ihnen angegebenen Standard aktualisiert werden.

Meiner Meinung nach ist dies also kein Fehler, und ich möchte nicht, dass EF meine Daten so aktualisiert, wie ich es nicht ausdrücklich vorschreibe. Der Entwickler ist dafür verantwortlich, das System anzuweisen, was mit den Daten zu tun ist.

Iravanchi
quelle
17
Für Leute, die diese Antwort über Google finden: Ich habe es gerade in EF6 versucht und die Update-Anweisung scheint (nicht mehr) notwendig zu sein. Ich denke, sie haben es doch als Fehler angesehen.
EPLKleijntjens
3
Dafür kann ich auch bürgen. Wenn Sie einen Standardwert auch für ein nullwertfähiges Feld benötigen, ändern Sie ihn einfach zuerst mit einem Standardwert in nicht nullwertfähig und dann wieder in nullwertfähig. Sehr praktisch, wenn Sie einer untergeordneten Klasse ein nicht nullbares Feld hinzugefügt haben :)
Wouter Schut
1
Genau die richtige Erklärung. AlterColumn () ändert nur die Spaltendefinition. Es hat keinerlei Auswirkungen auf vorhandene Datensätze
Korayem
9
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
quelle
2
Ähm ... danke, aber wie unterscheidet sich das von der Antwort von @ webdeveloper?
Andriy Drozdyuk
1
Es sagt Ihnen nicht, wo Sie den Standardwertparameter hinzufügen müssen
Pushpendra
1
@Pushpendra, es ist lustig, wie Entwickler dazu neigen zu vergessen, dass sie einst nicht viel wussten. Ich mag detaillierte Antworten, die alle Ebenen erfüllen. Exzellente Arbeit!
nützlichBee
5

Ich bin mir nicht sicher, ob diese Option immer verfügbar war, stieß aber auf ein ähnliches Problem. Ich stellte fest, dass ich den Standardwert festlegen konnte, ohne manuelle Updates mithilfe der folgenden Schritte auszuführen

defaultValueSql: "'NY'"

Ich habe eine Fehlermeldung erhalten, als der angegebene Wert angegeben wurde. "NY"Dann wurde mir klar, dass sie einen SQL-Wert erwarten, "GETDATE()"also habe ich es versucht "'NY'"und das hat den Trick getan

Die gesamte Linie sieht so aus

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

Dank dieser Antwort bin ich auf dem richtigen Weg

Workabyte
quelle
2

Seit EF Core 2.1 können Sie MigrationBuilder.UpdateDataWerte ändern, bevor Sie die Spalte ändern (sauberer als bei Verwendung von Raw SQL):

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
quelle
1

Ich habe festgestellt, dass es ausreicht, nur den Auto-Property Initializer für die Entitätseigenschaft zu verwenden, um die Aufgabe zu erledigen.

Beispielsweise:

public class Thing {
    public bool IsBigThing { get; set; } = false;
}
Velyo
quelle
2
Es ist eine gute Antwort (hat mir geholfen), aber dies fügt keinen Standardwert in der Datenbank hinzu, sondern legt den Wert im Code fest.
chris31389
Richtig, es wurde kein Standardwert in der Datenbank nach der Migration hinzugefügt
Chetan Chaudhari
1

Viele der anderen Antworten konzentrieren sich darauf, wie man manuell eingreift, wenn diese Probleme auftreten.

Nehmen Sie nach dem Generieren der Migration eine der folgenden Änderungen an der Migration vor:

  1. Ändern Sie die Spaltendefinition so, dass sie eine defaultValue- oder defaultSql-Anweisung enthält:
    AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false, default: ""));

  2. Fügen Sie eine SQL-Anweisung ein, um die vorhandenen Spalten vor der AlterColumn vorab zu füllen:
    Sql("UPDATE dbo.Movies SET Director = '' WHERE Director IS NULL");

Beachten Sie, dass manuelle Änderungen, die an einem Migrationsskript vorgenommen werden, überschrieben werden, wenn Sie die Migration erneut durchführen. Bei der ersten Lösung ist es ziemlich einfach, EF so zu erweitern, dass im Rahmen der Migrationsgenerierung automatisch ein Standardwert für ein Feld definiert wird.

HINWEIS: EF erledigt dies nicht automatisch für Sie, da die Standardwertimplementierung für jeden RDBMS-Anbieter unterschiedlich wäre, sondern auch, weil Standardwerte in einer reinen EF-Laufzeit weniger Bedeutung haben, da jede Zeileneinfügung den aktuellen Wert für jede Eigenschaft liefert. Selbst wenn es null ist, wird die Standardwertbeschränkung nie ausgewertet.
Diese AlterColumn-Anweisung ist das einzige Mal, dass die Standardeinschränkung ins Spiel kommt. Ich denke, dies hat für das Team, das die SQL Server-Migrationsimplementierung entworfen hat, eine niedrigere Priorität.

Die folgende Lösung kombiniert Attributnotation, Modellkonfigurationskonventionen und Spaltenanmerkungen, um Metadaten an einen benutzerdefinierten Migrationscodegenerator zu übergeben. Die Schritte 1 und 2 können für jedes betroffene Feld durch eine fließende Notation ersetzt werden, wenn Sie keine Attributnotation verwenden.
Hier sind viele Techniken im Spiel, zögern Sie nicht, einige oder alle zu verwenden. Ich hoffe, dass hier für alle ein Wert ist


  1. Deklarieren Sie den Standardwert.
    Erstellen Sie ein vorhandenes Attribut oder verwenden Sie es erneut, um den zu verwendenden Standardwert zu definieren. In diesem Beispiel erstellen wir ein neues Attribut namens DefaultValue, das von ComponentModel.DefaultValueAttribute erbt, da die Verwendung intuitiv ist und die Möglichkeit besteht, dass es vorhanden ist Codebasen implementieren dieses Attribut bereits. Bei dieser Implementierung müssen Sie nur dieses spezielle Attribut verwenden, um auf DefaultValueSql zuzugreifen, das für Datumsangaben und andere benutzerdefinierte Szenarien nützlich ist.

    Implementierung

    [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; }

    Attributdefinition

    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. Erstellen Sie eine Konvention, um den Standardwert in die Spaltenanmerkungen einzufügen.
    Spaltenanmerkungen werden verwendet, um benutzerdefinierte Metadaten zu Spalten an den Migrationsskriptgenerator weiterzuleiten.
    Die Verwendung einer Konvention zeigt die Leistungsfähigkeit der Attributnotation, um zu vereinfachen, wie fließende Metadaten für viele Eigenschaften definiert und bearbeitet werden können, anstatt sie für jedes Feld einzeln anzugeben.

    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. Hinzufügen der Konvention zum DbContext
    Es gibt viele Möglichkeiten, dies zu erreichen. Ich möchte die Konventionen als ersten benutzerdefinierten Schritt in meiner ModelCreation-Logik deklarieren. Dies wird in Ihrer DbContext-Klasse sein.

    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. Überschreiben des MigrationCodeGenerators
    Nachdem diese Anmerkungen auf die Spaltendefinitionen im Modell angewendet wurden, müssen Sie den Migrationsskriptgenerator ändern, um diese Anmerkungen zu verwenden. Dafür werden wir von der erben, System.Data.Entity.Migrations.Design.CSharpMigrationCodeGeneratorda wir nur eine minimale Menge an Änderungen injizieren müssen.
    Nachdem wir unsere benutzerdefinierte Anmerkung verarbeitet haben, müssen wir sie aus der Spaltendefinition entfernen, um zu verhindern, dass sie für die endgültige Ausgabe serialisiert wird.

    Weitere Informationen zur Verwendung finden Sie im Basisklassencode: 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. Registrieren des CustomCodeGenerator Im
    letzten Schritt müssen wir in der DbMigration-Konfigurationsdatei den zu verwendenden Codegenerator angeben und standardmäßig in Ihrem Migrationsordner nach Configuration.cs suchen ...

    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
quelle
0

Aus irgendeinem Grund, dass ich mich nicht erklären konnte, funktioniert die genehmigte Antwort für mich nicht mehr.

Es hat auf einer anderen App funktioniert, auf der, an der ich arbeite, funktioniert es nicht.

Eine alternative, aber recht ineffiziente Lösung wäre es, die SaveChanges () -Methode wie unten gezeigt zu überschreiben. Diese Methode sollte sich in der Context-Klasse befinden.

    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
quelle