Entity Framework – Seed – wypełnianie danymi

Podczas podejścia z migracjami tworzona jest klasa Configuration: DbMigrationsConfiguration<MyContext>, która posiada metodę Seed() służącą do wypełniania danymi początkowymi. Ta metoda uruchamia się po każdym „Update-Database”. Jeśli więc teraz dodaliśmy nowy kod do tej metody to wykona się ona na bazie podczas następnego update’u bazy.

AddOrUpdate

Esencją tego podejścia jest metoda AddOrUpdate():

protected override void Seed(BookService.Models.BookServiceContext context)
{
    context.Authors.AddOrUpdate(x => x.Id,
        new Author() { Id = 1, Name = "Jane Austen" },
        new Author() { Id = 2, Name = "Charles Dickens" },
        new Author() { Id = 3, Name = "Miguel de Cervantes" }
        );

    context.Books.AddOrUpdate(x => x.Id,
        new Book() { Id = 1, Title = "Pride and Prejudice", Year = 1813, AuthorId = 1, 
            Price = 9.99M, Genre = "Comedy of manners" },
        new Book() { Id = 2, Title = "Northanger Abbey", Year = 1817, AuthorId = 1, 
            Price = 12.95M, Genre = "Gothic parody" },
        new Book() { Id = 3, Title = "David Copperfield", Year = 1850, AuthorId = 2, 
            Price = 15, Genre = "Bildungsroman" }
        );
}

Dzięki niej symulujemy operację Upsert czyli gdy danych brak to wstawiamy, a gdy są to nadpisujemy. Pierwszy argument do tej metody służy właśnie do weryfikowania czy dany wiersz już istnieje. Najczęściej będziemy tam przekazywać klucz główny, ponieważ jest on unikalny.

Nie tylko po kluczu głownym

Gdy dodajemy użytkowników a nie wiemy jakie będą Id które nam baza przydzieli (bo jest ustawione Identity), to musimy polegać na czymś innym. Możemy wtedy przekazać inną unikalną kolumnę np UserLogin. Wtedy wyglądałoby to:

protected override void Seed(BookService.Models.BookServiceContext context)
{
    Author jane = new Author() { Name = "Jane Austen", Login = "jane.austen" };
    Author dickens = new Author() { Name = "Charles Dickens", Login = "charles.dickens" };

    context.Authors.AddOrUpdate(x => x.Login, new []{ jane, dickens });

    context.Books.AddOrUpdate(x => x.Id,
        new Book() { Id = 1, Title = "Pride and Prejudice", Year = 1813, AuthorId = jane.Id, 
            Price = 9.99M, Genre = "Comedy of manners" },
        new Book() { Id = 2, Title = "Northanger Abbey", Year = 1817, AuthorId = jane.Id, 
            Price = 12.95M, Genre = "Gothic parody" },
        new Book() { Id = 3, Title = "David Copperfield", Year = 1850, AuthorId = dickens.Id, 
            Price = 15, Genre = "Bildungsroman" }
        );
}

Ten przypadek bardziej odpowiada temu co jest w rzeczywistych produkcyjnych systemach.

Podzielę się kilkoma rzeczami które dopiero w trakcie korzystanie zrozumiałem:

  • nie działa tutaj dodawanie poprzez navigation properties. Zawsze musi to być ustawianie kolumny odpowiedzialnej za relacje (ForeignKey). Jak w przykładzie na górze „AuthorId = 1”. Może inaczej – zadziała za pierwszym razem, ale już się wywali podczas kolejnych uruchomień seeda.
  • gdy z poziomu Package Manager Console uruchamiamy Update-Database to nie zawsze widzimy gdzie wywaliła się metoda Seed. Możemy na jej początku umieścić:
    // Used for attaching with second VS when running migration and Update-Database
    //if (System.Diagnostics.Debugger.IsAttached == false)
    //    System.Diagnostics.Debugger.Launch();
    

    i odkomentować gdy coś sie wywala, odpali tam to drugiego Visual Studio, którym zdebugujemy pierwszego.

  • gdy nie mamy klucza głównego, albo używanie go nie ma sensu przy relacji wiele do wielu, możemy użyć kilku column na raz, np:
    context.UserRoles.AddOrUpdate(x => new { x.UserId, x.RoleId }, userRole);
    
  • AddOrUpdate() jako drugi parametr przyjmuje listę obiektów a nie tylko jeden obiekt. Przykłady, z których się uczyłem nie pokazały tego, a jedna pętla mniej zawsze cieszy 🙂
Reklamy
Ten wpis został opublikowany w kategorii Programowanie i oznaczony tagami , . Dodaj zakładkę do bezpośredniego odnośnika.