Praca ze stanami jednostek

W tym temacie opisano sposób dodawania i dołączania jednostek do kontekstu oraz sposobu, w jaki program Entity Framework przetwarza je podczas zapisywania zmian. Program Entity Framework zajmuje się śledzeniem stanu jednostek, gdy są one połączone z kontekstem, ale w scenariuszach rozłączonych lub N-warstwowych możesz poinformować ef o stanie, w którym powinny znajdować się jednostki. Techniki przedstawione w tym temacie dotyczą modeli utworzonych przy użyciu podejścia „najpierw kod” i narzędzia EF Designer.

Stany jednostek i SaveChanges

Jednostka może znajdować się w jednym z pięciu stanów zdefiniowanych przez wyliczenie EntityState. Są to następujące stany:

  • Dodano: jednostka jest śledzona przez kontekst, ale nie istnieje jeszcze w bazie danych
  • Niezmienione: jednostka jest śledzona przez kontekst i istnieje w bazie danych, a jej wartości właściwości nie uległy zmianie z wartości w bazie danych
  • Zmodyfikowane: jednostka jest śledzona przez kontekst i istnieje w bazie danych, a niektóre lub wszystkie jej wartości właściwości zostały zmodyfikowane
  • Usunięto: jednostka jest śledzona przez kontekst i istnieje w bazie danych, ale została oznaczona do usunięcia z bazy danych przy następnym wywołaniu funkcji SaveChanges
  • Odłączone: jednostka nie jest śledzona przez kontekst

Funkcja SaveChanges wykonuje różne czynności dla jednostek w różnych stanach:

  • Niezmienione jednostki nie są dotykane przez polecenie SaveChanges. Aktualizacje nie są wysyłane do bazy danych dla jednostek w stanie Niezmienione.
  • Dodane jednostki są wstawiane do bazy danych, a następnie stają się niezmienione po powrocie funkcji SaveChanges.
  • Zmodyfikowane jednostki są aktualizowane w bazie danych, a następnie stają się niezmienione po powrocie funkcji SaveChanges.
  • Usunięte jednostki są usuwane z bazy danych, a następnie odłączane od kontekstu.

W poniższych przykładach pokazano sposoby zmiany stanu jednostki lub grafu jednostki.

Dodawanie nowej jednostki do kontekstu

Nową jednostkę można dodać do kontekstu, wywołując metodę Add w zestawie dbSet. Spowoduje to przełączenie jednostki do stanu Dodano, co oznacza, że zostanie wstawiona do bazy danych przy następnym wywołaniu funkcji SaveChanges. Przykład:

using (var context = new BloggingContext())
{
    var blog = new Blog { Name = "ADO.NET Blog" };
    context.Blogs.Add(blog);
    context.SaveChanges();
}

Innym sposobem dodania nowej jednostki do kontekstu jest zmiana jego stanu na Dodano. Przykład:

using (var context = new BloggingContext())
{
    var blog = new Blog { Name = "ADO.NET Blog" };
    context.Entry(blog).State = EntityState.Added;
    context.SaveChanges();
}

Na koniec możesz dodać nową jednostkę do kontekstu, podłączając ją do innej jednostki, która jest już śledzona. Może to być dodanie nowej jednostki do właściwości nawigacji kolekcji innej jednostki lub ustawienie właściwości nawigacji referencyjnej innej jednostki w celu wskazania nowej jednostki. Przykład:

using (var context = new BloggingContext())
{
    // Add a new User by setting a reference from a tracked Blog
    var blog = context.Blogs.Find(1);
    blog.Owner = new User { UserName = "johndoe1987" };

    // Add a new Post by adding to the collection of a tracked Blog
    blog.Posts.Add(new Post { Name = "How to Add Entities" });

    context.SaveChanges();
}

Należy pamiętać, że w przypadku wszystkich tych przykładów, jeśli dodawana jednostka zawiera odwołania do innych jednostek, które nie zostały jeszcze śledzone, te nowe jednostki również zostaną dodane do kontekstu i zostaną wstawione do bazy danych przy następnym wywołaniu funkcji SaveChanges.

Dołączanie istniejącej jednostki do kontekstu

Jeśli masz już istniejącą jednostkę w bazie danych, ale która nie jest obecnie śledzona przez kontekst, możesz poinformować kontekst o śledzeniu jednostki przy użyciu metody Attach w zestawie dbSet. Jednostka będzie w stanie Niezmienione w kontekście. Przykład:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Blogs.Attach(existingBlog);

    // Do some more work...  

    context.SaveChanges();
}

Należy pamiętać, że żadne zmiany nie zostaną wprowadzone w bazie danych, jeśli funkcja SaveChanges zostanie wywołana bez wykonywania żadnych innych manipulacji dołączoną jednostką. Jest to spowodowane tym, że jednostka jest w stanie Niezmienione.

Innym sposobem dołączenia istniejącej jednostki do kontekstu jest zmiana jego stanu na Niezmienione. Przykład:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Entry(existingBlog).State = EntityState.Unchanged;

    // Do some more work...  

    context.SaveChanges();
}

Należy pamiętać, że w obu tych przykładach, jeśli dołączona jednostka ma odwołania do innych jednostek, które nie zostały jeszcze śledzone, te nowe jednostki również zostaną dołączone do kontekstu w stanie Niezmienione.

Dołączanie istniejącej, ale zmodyfikowanej jednostki do kontekstu

Jeśli masz już istniejącą jednostkę w bazie danych, ale do której zmiany mogły zostać wprowadzone, możesz poinformować kontekst o dołączeniu jednostki i ustawić jego stan na Zmodyfikowany. Przykład:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Entry(existingBlog).State = EntityState.Modified;

    // Do some more work...  

    context.SaveChanges();
}

Po zmianie stanu na Zmodyfikowany wszystkie właściwości jednostki zostaną oznaczone jako zmodyfikowane, a wszystkie wartości właściwości zostaną wysłane do bazy danych po wywołaniu funkcji SaveChanges.

Należy pamiętać, że jeśli dołączona jednostka zawiera odwołania do innych jednostek, które nie są jeszcze śledzone, te nowe jednostki zostaną dołączone do kontekstu w stanie Niezmienione — nie zostaną one automatycznie zmodyfikowane. Jeśli masz wiele jednostek, które należy oznaczyć jako Zmodyfikowane, należy ustawić stan dla każdej z tych jednostek osobno.

Zmienianie stanu śledzonej jednostki

Możesz zmienić stan jednostki, która jest już śledzona, ustawiając właściwość State w jej wpisie. Przykład:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Blogs.Attach(existingBlog);
    context.Entry(existingBlog).State = EntityState.Unchanged;

    // Do some more work...  

    context.SaveChanges();
}

Należy pamiętać, że wywołanie metody Dodaj lub Dołącz dla już śledzonej jednostki może służyć do zmiany stanu jednostki. Na przykład wywołanie funkcji Attach dla jednostki, która jest obecnie w stanie Dodano, spowoduje zmianę jego stanu na Niezmienione.

Wstaw lub zaktualizuj wzorzec

Typowym wzorcem dla niektórych aplikacji jest dodanie jednostki jako nowej (w wyniku wstawienia bazy danych) lub dołączenie jednostki jako istniejącej i oznaczenie jej jako zmodyfikowanej (w wyniku aktualizacji bazy danych) w zależności od wartości klucza podstawowego. Na przykład w przypadku używania wygenerowanych przez bazę danych kluczy podstawowych liczba całkowita często traktuje jednostkę z kluczem zerowym jako nową i jednostką z kluczem niezerowym jako istniejącą. Ten wzorzec można osiągnąć, ustawiając stan jednostki na podstawie sprawdzania wartości klucza podstawowego. Przykład:

public void InsertOrUpdate(Blog blog)
{
    using (var context = new BloggingContext())
    {
        context.Entry(blog).State = blog.BlogId == 0 ?
                                   EntityState.Added :
                                   EntityState.Modified;

        context.SaveChanges();
    }
}

Należy pamiętać, że po zmianie stanu na Zmodyfikowany wszystkie właściwości jednostki zostaną oznaczone jako zmodyfikowane, a wszystkie wartości właściwości zostaną wysłane do bazy danych po wywołaniu funkcji SaveChanges.