Audit z Entity Framework Plus

Wprowadzenie

Historia zmian danych w aplikacji wcześniej czy później pojawi się w każdym projekcie. Do tego problemu można podejść na różne sposoby – możemy samemu coś wymyślić lub skorzystać z czegoś gotowego. W przypadku gdy korzystamy z Entity Framework, możemy użyć mechanizmu audytu z darmowego rozszerzenia Entity Framework Plus. W dzisiejszym wpisie pokażę podstawy korzystania z tego mechanizmu, natomiast za tydzień rozbudujemy jego możliwości.

Problem

W tworzonych przez nas systemach bardzo często potrzebujemy wiedzieć, kto, kiedy i co zmienił. W zależności od potrzeb możemy przechowywać tylko informacje o użytkowniku, który dodał lub zmodyfikował dane, oraz kiedy dany użytkownik to zrobił. Z drugiej strony często potrzebujemy również wiedzieć, co się zmieniło.

Z jednej strony możemy skorzystać z dedykowanych do tego baz danych, jak na przykład Event Store (https://eventstore.org/), które mają takie funkcje z pudełka. Czasami chcemy zapisać te informacje w istniejącej bazie, bez konieczności jej zmiany. W przypadku gdy korzystamy z Entity Framework, dodanie tego mechanizmu jest relatywnie proste z rozszerzeniem Entity Framework Plus.

Zanim jednak przejdziemy do samej biblioteki, parę słów o testowym projekcie.

Utworzyłem prostą aplikację konsolową, która w bazie zapisuje informacje o produktach (w tym o kategorii, w jakiej się znajduje). Klasy modelu są bardzo proste i nieraz już gościły na blogu:

Początkowo obiekt kontekstu Entity Framework również jest standardowy:

Dodatkowo w projekcie włączony jest mechanizm migracji, który na końcu dodaje testowe dane z wykorzystaniem biblioteki Bogus.

W klasie program znajdują się trzy testowe metody, które posłużą nam do zapisania informacji o dodaniu, aktualizacji oraz usunięciu produktu. Później rozszerzymy ten kod o wyświetlanie informacji audytowych.

Darmowy kurs Visual Studio

Pracując z setkami programistów, zauważyłem, że większość osób nie pracuje efektywnie w Visual Studio. W skrajnych przypadkach korzystali z kopiowania z wykorzystaniem menu Edit. Wiem, że to dziwne, ale naprawdę niektórzy tak pracują. Dlatego postanowiłem stworzyć kurs Visual Studio – aby pomóc koleżankom i kolegom w efektywniejszej pracy.

Przygotowałem 20 lekcji e-mail, w których pokażę Ci, w jaki sposób pracować efektywniej i szybciej w Visual Studio. Poznasz dodatki, bez których nie wyobrażam sobie pracy w tym IDE.

Po więcej informacji zapraszam na dedykowaną stronę kursu: Darmowy Kurs Visual Studio.

Quiz C#

Ostatnio przygotowałem również quiz C#, w którym możesz sprawdzić swoją wiedzę. Podejmiesz wyzwanie?

Audit

Mechanizm Audit z Entity Framework Plus bardzo ułatwia zapisywanie informacji o zmianach w danych. Aby z niego skorzystać, należy przede wszystkim zainstalować odpowiedni pakiet z Nugeta. Wspierana jest wersja 5 oraz 6 Entity Framework. Możemy zainstalować cały Entity Framework Plus (Z.EntityFramework.Plus.EF6) lub tylko pakiet dla samego audytu (Z.EntityFramework.Plus.Audit.EF6).

Audyt udostępnia dwa nowe typy, które posłużą do przechowywania zmian. AuditEntry zapisuje informacje o zmienionym obiekcie (typ, jaki stan, kto i kiedy). Natomiast AuditEntryProperty służy do zapisania informacji o zmianach w właściwościach obiektu (stara – nowa wartość). Dlatego po  zainstalowaniu biblioteki musimy w obiekcie kontekstowym dodać dwie nowe właściwości dla tych dwóch typów.

Audyt umożliwia automatyczne dodawanie obiektów do zapisu historii. Aby to zadziałało, musimy zdefiniować statyczny delegat AutoSavePreAction z klasy AuditManager.DefaultConfiguration. Za pomocą niego możemy określić, dla których obiektów będziemy zapisywać historię (w przykładzie robimy to dla wszystkich obiektów). Ustawienie tego delegatu można zrobić w statycznym konstruktorze obiektu kontekstowego.

W przypadku gdy korzystamy z mechanizmu migracji, należy generować migrację, która doda odpowiednie tabele do bazy.

Mając już przygotowany obiekt kontekstowy, możemy zapisać dane w historii. Najprostszym sposobem jest utworzenie instancji klasy Audit, ustawienie nazwy aktualnie zalogowanego użytkownika i skorzystanie rozszerzonej wersji metody SaveChanges (dostarczonej przez bibliotekę). Poniżej znajduje się zmieniony kod testowej metody, która dodaje nowy produkt do bazy.

Poniżej znajduje się zawartość tych dwóch dodatkowych tabel po wykonaniu się powyższej metody:

audit database

Jak widać, zmieniony kod spowodował zapis historii w nowych tabelach. Ale niestety takie podejście ma też minus. Musimy zmienić każde wywołanie metody SaveChanges, co niestety może wymagać zmian w wielu miejscach w kodzie. Na szczęście można to zrobić jeszcze trochę inaczej.

Nadpisanie SaveChanges

Innym sposobem zapisu historii zmian jest nadpisanie metody SaveChanges, które będzie automatycznie zapisywała historię. Takie rozwiązanie jest dużo lepsze, ponieważ wystarczy zmienić kod aplikacji w jednym miejscu, co może być szczególnie przydatne w przypadku już istniejącej aplikacji.

Poniżej znajduje się nowa wersja obiektu kontekstowego z nadpisaną metodą SaveChanges:

W kodzie poza samą metodą pojawiał się jeszcze nowa właściwość o nazwie UserName. Posłuży nam ona do określenia nazwy aktualnie zalogowanego użytkownika. W realnej aplikacji będzie ona ustawiana przez kontener dependency injection (np. Autofac). W przykładzie ustawiamy domyślną wartość na System.

W metodzie SaveChanges na początku tworzymy, podobnie jak wcześniej, instancję klasy Audit i ustawiamy w niej nazwę użytkownika. Przed wywołaniem bazowej metody SaveChanges i po jej wywołaniu odpalamy metody na obiekcie klasy Audit (są one wykorzystywane przez dodatkowe funkcjonalności mechanizmu audytu).

Później sprawdzamy, czy ustawiony jest delegat dla automatycznego zapisu historii. Jeśli jest, to go odpalamy i później zapisujemy dane audytowe w bazie poprzez ponowne wywołanie metody SaveChanges z klasy bazowej.

Na samym końcu zwracamy z metody liczbę, którą przypisaliśmy do zmiennej lokalnej i w której znajduje się wartość zwrócona przez pierwsze wywołanie metody SaveChanges.

Pobieranie historii zmian

Na koniec pokażę Ci jeszcze, w jaki sposób pobrać historię zmian dla jakiegoś obiektu. W przykładzie w klasie Program znajduje się metoda ShowHistory, która przyjmuje id obiektu, dla którego ma zostać wyświetlona historia. W przykładzie jest to wartość zwrócona przez metodę AddTest i znajduje się tam id dodanego na początku obiektu.

Do wyświetlania historii możemy skorzystać z dodanej na początku wpisu właściwości AuditEntries. Możemy skorzystać z nowej wersji metody Where (dodanej jako extension method do typu DbSet<AuditEntry>), która jako parametr generyczny otrzymuje typ, dla jakiego chcemy pobrać historię. W normalnym parametrze przekazujemy id obiektu.

Mając już historię zmian, możemy po niej przejść i następnie dla każdej zmiany pobrać informacje o zmienionych właściwościach.

Poniżej znajduje się zrzut ekranu konsoli testowej aplikacji. Jak widać, historia danych została ładnie zapisana.

audit console

Przykład

Na githubie (https://github.com/danielplawgo/EFAudit) znajduje się przykład do tego wpisu. Po jego pobraniu należy w app.config ustawić connection string do testowej bazy danych. Po tym można już uruchomić aplikację, która doda, zedytuje oraz usunie produkt i na końcu wyświetli jego historię.

Aktualizacja: Przykład w tym momencie jest rozbudowanych o konfiguracje Audit, która jest opisane w wpisie: Konfiguracja Audit z Entity Framework Plus.

Podsumowanie

Historia zmian danych w aplikacji może się bardzo przydać. W przypadku gdy korzystamy z Entity Framework, w projekcie możemy wykorzystać mechanizm Audit z rozszerzenia Entity Framework Plus. Dzięki temu, pisząc tylko kilka linijek kodu, możemy zapisać historię zmiany danych w swojej aplikacji.

W kolejnym artykule pokazuje jak skonfigurować mechanizm Audit.

1 thought on “Audit z Entity Framework Plus

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *