Wartość domyślna dla pól wymaganych w migracji Entity Framework?


92

Dodałem [Required]adnotację danych do jednego z moich modeli w aplikacji ASP.NET MVC . Po utworzeniu migracji uruchomienie Update-Databasepolecenia powoduje następujący błąd:

Nie można wstawić wartości NULL do kolumny „Director”, tabela „MOVIES_cf7bad808fa94f89afa2e5dae1161e78.dbo.Movies”; kolumna nie zezwala na wartości null. UPDATE nie powiodło się. Oświadczenie zostało zakończone.

Jest to spowodowane tym, że niektóre rekordy mają w swoich Directorkolumnach wartość NULL . Jak mogę automatycznie zmienić te wartości na jakiegoś domyślnego reżysera (np. „John Doe”)?

Oto mój model:

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

a oto moja ostatnia migracja:

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

Odpowiedzi:


74

Jeśli dobrze pamiętam, coś takiego powinno działać:

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

Uwaga: Wartość parametru defaultValueSql jest traktowana jako dosłowna instrukcja SQL, więc jeśli wymaganą wartością jest łańcuch, jak w przykładzie John Doe, wówczas wokół wartości wymagane są pojedyncze cudzysłowy.


9
Ja też tak myślałem, ale to nie działa w przypadku istniejących płyt. Więc nadal pojawia się błąd.
Andriy Drozdyuk

@drozzy Może to błąd, jak tutaj: EF 4.3.1 Wyjątek migracji - AlterColumn defaultValueSql tworzy tę samą domyślną nazwę ograniczenia dla różnych tabel. Możesz aktualizować wiersze ze IS NULLsprawdzaniem za pomocą zapytania.
webdeveloper

Ciekawe, ale nie jestem pewien, czy rozumiem, o czym mówią. Jeśli jednak jest to błąd, to tak, miałoby to sens.
Andriy Drozdyuk

6
Myślę, że powinno być: "'John Doe'"- musisz używać cudzysłowów SQL.
Sean

1
@webdeveloper, nie sądzę, że to błąd, po co AlterColumnaktualizować aktualne wartości? Jest to polecenie DDL (nie DML).
Anton

110

Oprócz odpowiedzi z @webdeveloper i @Pushpendra, musisz ręcznie dodać aktualizacje do migracji, aby zaktualizować istniejące wiersze. Na przykład:

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

Dzieje się tak, ponieważ AlterColumngeneruje DDL, aby ustawić wartość domyślną kolumny na określoną wartość w specyfikacji tabeli. DDL nie wpływa na istniejące wiersze w bazie danych.

W rzeczywistości wprowadzasz dwie zmiany w tym samym czasie (ustawiając wartość domyślną i ustawiając kolumnę jako NIE NULL) i każda z nich jest ważna indywidualnie, ale ponieważ wprowadzasz dwie zmiany w tym samym czasie, możesz oczekiwać, że system ' inteligentnie „zrealizuj swój zamiar i ustaw wszystko NULL wartości na wartości domyślne, ale nie jest to oczekiwane przez cały czas.

Załóżmy, że ustawiasz tylko domyślną wartość kolumny i nie ustawiasz jej jako NIE NULL. Oczywiście nie oczekujesz, że wszystkie rekordy NULL zostaną zaktualizowane zgodnie z podanymi wartościami domyślnymi.

Tak więc, moim zdaniem, nie jest to błąd i nie chcę, aby EF aktualizował moje dane w sposób, którego wyraźnie mu nie nakazuję. Deweloper jest odpowiedzialny za poinstruowanie systemu, co ma zrobić z danymi.


17
Dla osób, które znalazły tę odpowiedź przez Google: właśnie wypróbowałem to w EF6 i oświadczenie o aktualizacji nie wydaje się być konieczne (już). Myślę, że mimo wszystko uznali to za błąd.
EPLKleijntjens

3
Za to też mogę ręczyć. Jeśli potrzebujesz wartości domyślnej nawet dla pola dopuszczającego wartość null, po prostu zmień ją najpierw na nie dopuszczającą wartości null z wartością domyślną, a następnie zmień ją z powrotem na dopuszczającą wartość null. Bardzo przydatne, gdy dodałeś pole niepodlegające wartości null do klasy podrzędnej :)
Wouter Schut

1
Miejsce na wyjaśnienie. AlterColumn () po prostu zmienia definicję kolumny. Nie ma to żadnego wpływu na istniejące rekordy
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());       
    }
}

2
Hm ... dzięki, ale czym się to różni od odpowiedzi @ webdevelopera?
Andriy Drozdyuk

1
nie mówi ci, gdzie musisz dodać parametr wartości domyślnej
Pushpendra

1
@Pushpendra, to zabawne, jak programiści zapominają, że kiedyś niewiele wiedzieli. Lubię szczegółowe odpowiedzi na wszystkie poziomy. Świetna robota!
przydatneBee

5

nie jestem pewien, czy ta opcja była zawsze dostępna, ale właśnie napotkałem podobny problem, stwierdziłem, że udało mi się ustawić wartość domyślną bez uruchamiania jakichkolwiek aktualizacji ręcznych za pomocą następującego

defaultValueSql: "'NY'"

Wystąpił błąd, gdy podana wartość została "NY"następnie zdałem sobie sprawę, że spodziewają się wartości SQL, "GETDATE()"tak jak próbowałem "'NY'"i to załatwiło sprawę

cała linia wygląda tak

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

Dzięki tej odpowiedzi trafiłem na właściwą ścieżkę


2

Zauważyłem, że samo użycie Auto-Property Initializer na właściwości jednostki wystarczy, aby wykonać zadanie.

Na przykład:

public class Thing {
    public bool IsBigThing { get; set; } = false;
}

2
To dobra odpowiedź (pomogła mi), ale to nie dodaje wartości domyślnej w bazie danych, ustawia wartość w kodzie.
chris31389

racja, nie dodała wartości domyślnej do bazy danych po zmianach migracji
Chetan Chaudhari

2

Wiele innych odpowiedzi koncentruje się na ręcznej interwencji, gdy wystąpią te problemy.

Po wygenerowaniu migracji wykonaj jedną z następujących zmian migracji:

  1. Zmodyfikuj definicję kolumny, aby zawierała instrukcję defaultValue lub defaultSql:
    AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false, default: ""));

  2. Wstrzyknij instrukcję SQL, aby wstępnie wypełnić istniejące kolumny, przed AlterColumn:
    Sql("UPDATE dbo.Movies SET Director = '' WHERE Director IS NULL");

Należy pamiętać, że ręczne zmiany zastosowane do skryptu migracji zostaną nadpisane, jeśli ponownie utworzysz szkielet migracji. W przypadku pierwszego rozwiązania dość łatwo jest rozszerzyć EF, aby automatycznie zdefiniować wartość domyślną w polu w ramach generowania migracji.

UWAGA: EF nie robi tego automatycznie, ponieważ implementacja wartości domyślnej byłaby inna dla każdego dostawcy RDBMS, ale także dlatego, że wartości domyślne mają mniejsze znaczenie w czystym środowisku wykonawczym EF, ponieważ każda wstawka wiersza zapewni bieżącą wartość dla każdej właściwości, nawet jeśli ma wartość null, więc ograniczenie wartości domyślnej nigdy nie jest oceniane.
Ta instrukcja AlterColumn to jedyny przypadek, w którym domyślne ograniczenie wchodzi w grę, wydaje mi się, że stało się to niższym priorytetem dla zespołu, który zaprojektował implementację migracji SQL Server.

Poniższe rozwiązanie łączy notację atrybutów, konwencje konfiguracji modelu i adnotacje kolumn w celu przekazania metadanych do niestandardowego generatora kodu migracji. Kroki 1 i 2 można zastąpić płynną notacją dla każdego pola, którego dotyczy problem, jeśli nie używasz notacji atrybutów.
W grze jest wiele technik, możesz użyć niektórych lub wszystkich, mam nadzieję, że każdy tutaj ma wartość


  1. Zadeklaruj wartość domyślną
    Utwórz lub zmień przeznaczenie istniejącego atrybutu, aby zdefiniować wartość domyślną do użycia, w tym przykładzie utworzymy nowy atrybut o nazwie DefaultValue, który dziedziczy po ComponentModel.DefaultValueAttribute, ponieważ użycie jest intuicyjne i istnieje prawdopodobieństwo, że istnieje bazy kodu już implementują ten atrybut. W przypadku tej implementacji wystarczy użyć tego konkretnego atrybutu, aby uzyskać dostęp do DefaultValueSql, co jest przydatne w przypadku dat i innych niestandardowych scenariuszy.

    Realizacja

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

    Attrribute Definition

    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. Utwórz konwencję wstrzyknięcia wartości domyślnej do adnotacji
    kolumn. Adnotacje kolumn są używane do przekazywania niestandardowych metadanych dotyczących kolumn do generatora skryptów migracji.
    Użycie w tym celu konwencji demonstruje moc kryjącą się za notacją atrybutów, aby uprościć sposób definiowania i manipulowania płynnymi metadanymi dla wielu właściwości, zamiast określania ich indywidualnie dla każdego pola.

    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. Dodaj konwencję do DbContext
    Istnieje wiele sposobów, aby to osiągnąć. Lubię deklarować konwencje jako pierwszy niestandardowy krok w mojej logice ModelCreation, będzie to w Twojej klasie 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. Zastąp MigrationCodeGenerator
    Teraz, gdy te adnotacje zostały zastosowane do definicji kolumn w modelu, musimy zmodyfikować generator skryptów migracji, aby używał tych adnotacji. W tym celu odziedziczymy po tym, System.Data.Entity.Migrations.Design.CSharpMigrationCodeGeneratorjak musimy wprowadzić minimalną ilość zmiany.
    Po przetworzeniu naszej niestandardowej adnotacji musimy usunąć ją z definicji kolumny, aby zapobiec jej serializacji do ostatecznego wyniku.

    Zobacz kod klasy bazowej, aby poznać inne zastosowania: 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. Zarejestruj CustomCodeGenerator
    Ostatni krok, w pliku konfiguracyjnym DbMigration musimy określić generator kodu, który ma być używany, domyślnie poszukaj pliku Configuration.cs w folderze migracji ...

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

2

Od EF Core 2.1 można użyć MigrationBuilder.UpdateDatado zmiany wartości przed zmianą kolumny (czystsze niż przy użyciu surowego kodu 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);
}

0

Z jakiegoś powodu nie mogłem się wytłumaczyć, zaakceptowana odpowiedź już mi nie odpowiada.

Zadziałało w innej aplikacji, ale na tej, na której pracuję, nie działa.

Tak więc alternatywnym, ale dość nieefektywnym rozwiązaniem byłoby zastąpienie metody SaveChanges (), jak pokazano poniżej. Ta metoda powinna znajdować się w klasie 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";
            }
        }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.