W każdej aplikacji, wykorzystującej bazę danych do przechowywania informacji, są elementy/tabele/struktury, których zawartość zmienia się niezmiernie rzadko. W związku z tym, zasadne wydaje się zaimplementowanie mechanizmu przechowywania tychże informacji w “bardziej stałym” obiekcie. Ograniczyłoby to komunikację pomiędzy bazą danych i aplikacją, a tym samym zwiększyło wydajność aplikacji. Mechanizm taki można zaimplementować na wiele sposobów. Jednym z nich może być klasa typu Manager do przechowywania i zarządzania informacjami. Ja natomiast pokusiłem się o implementację typu cache, którą prezentuję poniżej.
Rozpoczynamy dodając nową klasę do logiki biznesowej (zakładam, że tam jest najwłaściwsze miejsce), której nadajemy modyfikatory internal (aby klasa była dostępna tylko z tego samego assembly) oraz static (by w aplikacji istniała tylko jedna instancja tejże klasy). Następnie dodajemy kluczowe pola odpowiedzialne za działanie klasy typu cache: interwał odświeżania danych, datę ostatniego odświeżenia, znacznik czy dane należy odświeżyć oraz property zwracające obiekt z naszego cacheu. Dodatkowo dodałem zmienną typu object w celu poprawnej synchronizacji wątku za pomocą słowa kluczowego lock. Impelmentacja tych elementów wygląda następująco:
internal static class SomeDataCache { private const int REFRESH_INTERVAL_MIN = 30; private static DataSet _Data; private static bool _NeedRefresh; private static DateTime? _LastRefreshTime; private static object _SyncRoot = new object(); public static DataSet Model { get { lock (_SyncRoot) { if (_Data == null || _NeedRefresh) { _Data = ReadDataFromDatabase(); _LastRefreshTime = DateTime.Now; } return _Data.Copy(); } } } public static void SetDirty() { _NeedRefresh = true; } private static DataSet ReadDataFromDatabase() { //return some data } }
Brakuje jeszcze kodu odpowiedzialnego za sprawdzanie czy nasz obiekt nie uległ przedawnieniu. Implementacja nie powinna sprawić trudności. Moja przedstawia się jak poniżej:
private static bool IsOutOfDate() { return _LastRefreshTime.HasValue && _LastRefreshTime.Value.AddMinutes(REFRESH_INTERVAL_MIN) < DateTime.Now; }
Oczywiście trzeba dodać jej wywołanie w property zwracającym obiekt.
Załóżmy sytuację, że mamy znacznik na bazie, informujący o tym, iż dane zostały zmienione. W tym przypadku należy napisać kolejny kod, odpowiedzialny za sprawdzanie tej flagi. Ja dodałem kolejny interwał oraz datę ostatniego sprawdzania znacznika. I na koniec implementacja metody do sprawdzania pola.
private const int CHECK_INTERVAL_SEC = 60; private static DateTime? _LastCheckTime; private static bool DataHaveChanged() { if (_LastCheckTime.HasValue && _LastCheckTime.Value.AddSeconds(CHECK_INTERVAL_SEC) >= DateTime.Now) { return false; } //check flag and return bool }
Tak jak w przypadku metody IsOutOfDate() powyższą należy również wywołać w property.