Blog Dla Programistów C#/.NET

wtorek, 3 lutego 2026

W typowych aplikacjach usuwanie rekordu z bazy danych oznacza jego trwałe skasowanie. Czasem jednak zależy nam, aby usunąć dane tylko pozornie, pozostawiając je w bazie do ewentualnego przywrócenia lub do celów audytowych. Takie podejście nazywamy soft delete (miękkim usunięciem). Zamiast trwale usuwać rekord SQL-em DELETE, oznaczamy go specjalną flagą, np. IsDeleted = true, dzięki czemu dane "ukrywamy", ale nie tracimy ich całkowicie. W efekcie aplikacja pomija tak oznaczone rekordy przy pobieraniu danych, ale w razie potrzeby możemy je łatwo przywrócić, zmieniając flagę na false.

Soft Delete w EF Core - Usuwanie Danych Bez Utraty Historii

Co to jest soft delete i dlaczego warto?


Soft delete to strategia przechowywania danych, w której rekordy nie są fizycznie usuwane z bazy, a jedynie oznaczane jako usunięte. Rozwiązanie to ma kilka istotnych zalet:
    
Możliwość odzyskania danych: Jeśli użytkownik usunie coś przez pomyłkę, dane można przywrócić poprzez zmianę flagi, ponieważ nie zostały trwale skasowane. To zapewnia swoisty rollback usunięcia.
    
Audyt i historia: Oznaczone rekordy nadal istnieją w bazie, więc można je wykorzystać do celów audytowych lub historycznych (np. sprawdzić, kto i kiedy oznaczył rekord jako usunięty).
    
Unikanie kaskadowych usunięć: Twarde (fizyczne) usunięcie może pociągać za sobą kaskadowe kasowanie powiązanych danych, co bywa niebezpieczne. Soft delete zapobiega utracie powiązanych informacji. Rekord nadal istnieje, więc relacje pozostają nienaruszone.

Podsumowując, miękkie usuwanie zwiększa bezpieczeństwo danych. Zamiast usuwać - oznaczamy, że są usunięte. Teraz zobaczmy, jak zaimplementować to podejście w praktyce z użyciem Entity Framework Core (EF Core).


Implementacja soft delete w EF Core


Platforma .NET i EF Core oferują wygodne mechanizmy, aby wdrożyć soft delete bez nadmiernego komplikowania kodu. Poniżej przedstawiam kroki implementacji miękkiego usuwania na prostym przykładzie (np. w aplikacji ASP.NET Core z bazą danych):
    
1. Dodanie flagi w modelu: Dodaj do swoich modeli encji (np. klasy reprezentującej tabelę) właściwość logiczną IsDeleted. Będzie ona wskazywać, czy dany rekord został "usunięty" miękko. Przykład:

public class Blog  /* przykładowa encja */
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsDeleted { get; set; } = false; /* domyślnie false */
}

Powyżej klasa Blog ma nową kolumnę IsDeleted. Gdy wartość true, rekord uznajemy za usunięty logicznie.
    
2. Globalny filtr zapytań: Skonfiguruj kontekst bazy danych, aby EF Core automatycznie filtrował rekordy oznaczone jako usunięte. Można to zrobić, dodając globalny filtr w metodzie OnModelCreating w klasie kontekstu:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasQueryFilter(b => !b.IsDeleted);
}

Powyższa konfiguracja oznacza: dla encji Blog każdorazowo przy zapytaniu dodawaj warunek WHERE IsDeleted == false. Innymi słowy, EF Core domyślnie pomija rekordy, które mają IsDeleted = true. Dzięki temu nie musimy za każdym razem pamiętać o dopisywaniu warunku w kodzie. Filtr działa globalnie w całej aplikacji. Gdy wykonamy np. context.Blogs.ToList(), otrzymamy tylko blogi nieusunięte.
    
3. Oznaczanie rekordu jako usuniętego: W momencie, gdy chcemy "usunąć" dany obiekt, zamiast usuwać go fizycznie z bazy, powinniśmy ustawić jego flagę IsDeleted na true. Można to zrobić na dwa sposoby:

-Ręczne oznaczenie: Pobieramy obiekt, ustawiamy mu IsDeleted = true i zapisujemy zmiany. Np.:

var blog = await context.Blogs.FirstOrDefaultAsync(b => b.Id == id);
if(blog != null)
{
blog.IsDeleted = true;
await context.SaveChangesAsync();
}

Taki kod ustawi flagę i dzięki globalnemu filtrowi dany rekord nie będzie już pojawiał się w wynikach zwykłych zapytań.

 -Nadpisanie metody SaveChanges: Możemy pójść o krok dalej i zautomatyzować soft delete, przechwytując operację usunięcia. W klasie naszego DbContext nadpisujemy metodę SaveChanges/SaveChangesAsync, aby wychwycić encje oznaczone do usunięcia i zamiast kasować, ustawić im flagę:

public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries<Blog>()
.Where(e => e.State == EntityState.Deleted))
{
/* Zamiast usuwać, oznacz jako zmodyfikowany i ustaw IsDeleted */
entry.State = EntityState.Modified;
entry.CurrentValues["IsDeleted"] = true;
}
return base.SaveChanges();
}

Powyżej iterujemy przez śledzone encje, których stan to Deleted (usunięte) i zamieniamy je na Modified (zmodyfikowane), jednocześnie ustawiając wartość IsDeleted na true. Dzięki temu możesz w kodzie aplikacji używać standardowego context.Remove(obj) czy context.YourEntities.Remove(obj), a kontekst EF Core i tak zamieni to pod spodem na soft delete. Nie musisz pamiętać o ręcznym ustawianiu flagi za każdym razem.
    
4. Pobieranie również usuniętych danych (gdy potrzebne): Zdarzają się sytuacje, że zechcesz jednak wyciągnąć także rekordy oznaczone jako usunięte, na przykład w panelu administratora lub do celów analitycznych. Wtedy EF Core umożliwia lokalne wyłączenie globalnego filtra za pomocą metody .IgnoreQueryFilters(). Przykład:

/* pobierz wszystkie blogi, łącznie z tymi miękko usuniętymi: */
var allBlogs = await context.Blogs
.IgnoreQueryFilters()
.ToListAsync();

Po dodaniu IgnoreQueryFilters() zapytanie zignoruje globalne filtry i zwróci pełen zestaw danych, włącznie z rekordami o IsDeleted = true. Domyślnie jednak, bez wywołania tej metody, filtry pozostają aktywne, co chroni przed przypadkowym wykorzystaniem "usuniętych" danych w aplikacji.


Podsumowanie


Soft delete to prosty, ale potężny wzorzec, który pozwala bezpiecznie usuwać dane bez ich utraty. Dzięki EF Core wdrożenie go jest stosunkowo łatwe, wystarczy dodatkowa kolumna oraz globalny filtr. W zamian zyskujemy możliwość przywracania omyłkowo usuniętych informacji i pełniejszy obraz danych na potrzeby audytu. Wiele nowoczesnych aplikacji wykorzystuje miękkie usuwanie, aby chronić wrażliwe lub ważne dane przed nieodwracalnym skasowaniem.

Jeśli interesują Cię praktyczne aspekty programowania w .NET (takie jak powyższe techniki) i chcesz od podstaw nauczyć się tworzyć aplikacje, warto skorzystać z kompleksowego szkolenia. W moim szkoleniu online "Zostań Programistą .NET" pokazuję krok po kroku cały proces nauki - od absolutnych podstaw do pierwszej pracy jako programista, w zaledwie 15 tygodni. To świetna opcja, by uporządkować wiedzę i nauczyć się dobrych praktyk w realnych projektach.

Autor artykułu:
Kazimierz Szpin
Kazimierz Szpin
CTO & Founder - FindSolution.pl
Programista C#/.NET. Specjalizuje się w Blazor, ASP.NET Core, ASP.NET MVC, ASP.NET Web API, WPF oraz Windows Forms.
Autor bloga ModestProgrammer.pl
Dodaj komentarz

Wyszukiwarka

© Copyright 2026 modestprogrammer.pl | Sztuczna Inteligencja | Regulamin | Polityka prywatności. Design by Kazimierz Szpin. Wszelkie prawa zastrzeżone.