Najlepszy sposób na odniesienie do statycznej bazy danych w kodzie?


24

Wiele aplikacji zawiera „dane statyczne”: dane, które tak naprawdę nie zmieniają się w trakcie życia aplikacji. Na przykład może istnieć lista obszarów sprzedaży, która prawdopodobnie będzie stałą listą w dającej się przewidzieć przyszłości.

Często zdarza się, że te dane statyczne znajdują się w tabeli bazy danych (często dlatego, że chcesz się do nich odwoływać w kluczach obcych innych tabel). Prosta przykładowa tabela będzie miała identyfikator, który będzie używany jako klucz podstawowy i opis. Na przykład twoja tabela SalesArea będzie miała (przynajmniej) kolumnę SalesAreaId i kolumnę SalesAreaDescription.

Teraz w kodzie możesz nie chcieć traktować każdego wiersza tabeli tak samo. Na przykład możesz chcieć ustawić domyślny Obszar Sprzedaży na niektórych ekranach, podać różne liczby dla niektórych obszarów lub ograniczyć to, co użytkownicy mogą robić w innych obszarach.

Jaki jest najlepszy sposób odwoływania się do tych danych statycznych w kodzie? Czemu?

  1. Zakoduj opisy w swoim kodzie. Użyj tego, aby wyszukać SalesAreaId z bazy danych, gdy jej potrzebujesz.
  2. Zakoduj identyfikatory w swoim kodzie. Skorzystaj z tego, aby wyszukać opis SalesAreaDescription, gdy go potrzebujesz.
  3. Dodaj kolumnę do tabeli dla każdego celu, np. Kolumnę „IsDefaultOnProductLaunchScreen” i tak dalej (może być ich wiele).
  4. Coś innego.

Czy są jakieś inne specjalne uwagi, które powinienem wziąć pod uwagę, mając do czynienia ze statycznymi danymi z bazy danych? Na przykład, nadając tym tabelom specjalną nazwę?


1
Możliwy duplikat: programmers.stackexchange.com/questions/304169/… Wierzę, że odpowiedzi na ten (połączony) trafiają do sedna problemu trochę lepiej IMO
JoeCool

Odpowiedzi:


14

Co powiesz na załadowanie ich do pamięci podręcznej (zwykle implementowanej jako tabela skrótów) podczas uruchamiania aplikacji? Jeśli to zrobisz, nie musisz nawet sprawdzać bazy danych (cóż, nie więcej niż raz).

Sugerowałbym także unikanie twardego kodowania czegokolwiek. Dodaj domyślne wskaźniki (początkowo w tabeli DB, a także w strukturze pamięci podręcznej) dla ekranów, które wymagają ustawień domyślnych. Aby wyszukiwać pliki bez defauiltu, spróbuj zapisać klucze, które będą wyszukiwane w pliku konfiguracji lub właściwości, jeśli możesz.


Buforowanie jest oczywiście dobre, ale jak zaktualizować te wartości? Przypuszczalnie restart aplikacji lub strategia unieważnienia pamięci podręcznej?
Steve

1
@ Steve Tak, dokładnie. Zależy od aplikacji. Ponowne uruchomienie jest dobre dla czegoś, co zaczyna się często. W przypadku aplikacji działającej długo, być może ponowne ładowanie pamięci podręcznej raz dziennie w wolnym czasie. Moje pytanie brzmi: co ze scenariuszem, w którym aplikacja działa przez wiele bardzo krótkich czasów życia. Na przykład skrypt PHP lub coś podobnego.
tylermac

Baza danych uruchomi własną pamięć podręczną dla często używanych danych, więc ponownie wdrożysz coś, co już zostało zaimplementowane (i prawdopodobnie nie tak dobrze!)
James Anderson

@JamesAnderson: buforowanie w środkach aplikacji nie będzie tylko kiedykolwiek być jedno połączenie do bazy danych. Tak, bazy danych będą miały własne pamięci podręczne, ale mogą one zostać unieważnione / odświeżone przez zdarzenia poza kontrolą Twojej aplikacji, a Ty nadal musisz mieć połączenie z bazą danych i wykonać zapytanie, aby uzyskać te dane (i mam nadzieję , że jest w pamięć podręczna db). Zaimplementowanie prostej pamięci podręcznej w aplikacji nie jest wcale takie trudne.
FrustratedWithFormsDesigner

7

Alternatywą dla DB lub twardego kodowania jest użycie pliku konfiguracyjnego odczytanego podczas uruchamiania. Następnie możesz przechowywać te dane w strukturze tylko do odczytu w kodzie.

W rzadkim (ale nie niemożliwym) przypadku, w którym edytujesz te dane, musisz ponownie uruchomić aplikację. Jeśli nie jest to możliwe, możesz napisać bardziej złożony menedżer konfiguracji, który sprawdza zmiany w pliku konfiguracyjnym przy każdym dostępie do danych, jest to w rzeczywistości całkiem wydajne, ponieważ wystarczy sprawdzić znacznik czasu w pliku, a następnie unieważnić wszystkie dane jeśli plik zostanie zaktualizowany.


1
Dobry pomysł na niektóre typy danych statycznych, ale nie tak dobry, jeśli chcesz wymusić relacje FK zgodnie z opisem w pytaniu.
Kramii przywraca Monikę

Pytanie nie mówiło, że był to wymóg, tylko scenariusz. Jeśli nie jest to konieczne, podejście do pliku konfiguracyjnego działa dobrze.
Steve

Masz rację, nie byłem wystarczająco jasny. Ale cieszę się ... ponieważ nauczyłem się czegoś z twojej odpowiedzi. Nigdy wcześniej nie spotkałem się z takim podejściem.
Kramii przywraca Monikę

3

Jeśli dane odnoszą się do istniejących danych w bazie danych, prawdopodobnie równie skuteczne jest dodanie ich do bazy danych, jak i dodanie jej do kodu. Jeśli tak się nie stanie, zwykle kusi mnie, aby „raz wziąć tę kulę” i umieścić ją w kodzie do pierwszej zmiany.

Często okazuje się, że to, co uważamy za statyczne, nie jest, a kiedy tak się dzieje, nie trzeba czekać na wydanie kodu, aby wprowadzić zmiany. Gdy tylko to się stanie, umieść go w bazie danych i napisz stronę administratora, aby dokonać dalszych aktualizacji.

Na przykład, jeśli masz już Obszary sprzedaży w DB, dodaj tam opis, nie buduj tabeli skrótów, aby powiązać dane bazy danych z listami zakodowanymi na stałe. Ale jeśli nie zbudujesz tabeli skrótów Obszarów sprzedaży, ale bądź gotowy, za pierwszym razem, gdy ktoś zmieni opis lub doda nowy Obszar sprzedaży, przenieś go do bazy danych.


„Często to, co naszym zdaniem będzie statyczne, okazuje się nie być” - tak prawdziwe.
Kramii przywraca Monikę

3

Dlaczego nie po prostu wszystko napisać na sztywno? Głównym problemem, który zawsze miałem, jest odwoływanie się do wartości statycznych z bazy danych w kodzie aplikacji. To jedno, jeśli budujesz bezpośrednio listę rozwijaną lub coś z wartości statycznych, ale co, jeśli logika aplikacji zależy od wartości z bazy danych?

W prostej aplikacji mam obecnie listę stanów edycji fragmentów treści: Szkic, Opublikowane, Zarchiwizowane.

Elementy treści muszą być traktowane w różny sposób w zależności od stanu, w jakim się znajdują. Gdybym miał zachować dane o tym stanie w DB, odpowiednio o wartościach 1, 2, 3, jak bym sprawdził, czy coś jest w wersji roboczej stan?

if (content.State == 1)
czy
if (content.State == "Draft")?

Właśnie zapisałem wartości na stałe!
To samo, jeśli używasz tabeli pamięci podręcznej / skrótu: nadal musisz użyć wartości zapisanej w kodzie jako klucza do wyszukiwania danych.

Jakie są wady podejścia kodującego?


Wadą jest to, co powiedział pdr: „Często to, co naszym zdaniem będzie statyczne, okazuje się nie być”.
tylermac

2
Ale jeśli faktycznie odwołujesz się do wartości danych statycznych w kodzie, nie możesz go zmienić w bazie danych bez uszkodzenia aplikacji. Z pewnością zależy to od tego, do czego dane są wykorzystywane: jak wspomniałem powyżej, jeśli po prostu wypełnia element interfejsu użytkownika, aby użytkownik mógł wybrać wartość i przekazać ją bezpośrednio do bazy danych jako część rekordu w innej tabeli , dane statyczne w bazie danych mogą się zmieniać niezależnie od kodu aplikacji. Jestem prawie pewien, że taka jest sytuacja @pdr: aplikacja obsługująca zestaw danych statycznych jako pojedynczy element.
Dave

2

Podobnie do tego, co powiedział FrustratedWithFormsDesigner, zwykle odbywa się to za pomocą pamięci podręcznej, ponieważ oznacza to, że zawsze trzeba ładować dane statyczne tylko raz, ale jest zgodny ze wzorcem OAOO, co oznacza, że ​​nie definiujemy danych w dwóch miejscach (baza danych i Twój kod).

Wiem, że NHibernate ORM oferuje tę funkcjonalność poprzez pamięć podręczną drugiego poziomu . Możesz nakazać buforowanie danych z określonej tabeli i powiedzieć, że jest ona tylko do odczytu. Zostanie załadowany za pierwszym razem, gdy będzie wymagany, i nie trafi później do bazy danych, nawet jeśli uzyskasz dostęp do danych z wielu sesji.


+1 za raz i tylko raz. Ale co z traktowaniem różnych rzędów inaczej?
Kramii przywraca Monikę

1
@Kramii - Możesz użyć czegoś takiego jak klasy wyliczeniowe . Jeśli metadane dotyczą tylko twojego programu, umieściłbym logikę biznesową ( IsDefaultOn...) we właściwości na encji. Niech zwróci wartość true dla jednego bytu. To pozwoli ci znaleźć ten byt, biorąc pod uwagę całą kolekcję. Lub możesz użyć klasy kontrolera, która zapewni ci odpowiednią jednostkę z wywołaniem metody.
Scott Whitlock

2

Jest to przedwczesna optymalizacja w najgorszym przypadku.

Po pierwsze, każdy nowoczesny DBMS pobierze dane z małych tabel z prędkością błyskawicy i wszystkie mają algorytmy buforowania od dobrego do doskonałego (im więcej zapłaciłeś za DBMS, tym lepsze buforowanie!). Optymalizujesz więc coś, co zużywa minimalne zasoby.

Po drugie, masz bardzo małe doświadczenie z rzeczywistymi aplikacjami biznesowymi, jeśli wyobrażasz sobie, że „strefa sprzedaży” to dane statyczne. Mogą ulec zmianie przy każdej zmianie dyrektora marketingu lub dyrektora generalnego. Kierujesz się w świat bólu dwa lata później.

Są tylko dwa sposoby, aby przejść tutaj: -

Przechowuj go w bazie danych i uzyskuj dostęp do danych za pomocą „normalnego” sql.

Przechowuj go w fantazyjnym pliku konfiguracyjnym XML (możliwy dostęp poprzez REST lub SOAP), który można łatwo edytować za każdym razem, gdy nastąpi „strategiczna zmiana polityki”.


1

To zależy od tego, co robisz z danymi. Jeśli jest to lista czegoś, zwykle przeciągam ją do tablicy. Jeśli lista musi się rozwijać w innej wersji, łatwo jest po prostu dodać ją do bazy danych i zmienić kod, aby obsłużyć dodatkowe dane w tablicy (co może nawet nie być konieczne w zależności od kodu, np. Wyświetlenie listy za pomocą dla pętli za pomocą górnej granicy tablicy). Jeśli jest to lista ustawień, zwykle koduję je na stałe, ponieważ zwykle nie ma ich wiele i jest łatwiejsze i szybsze niż używanie instrukcji SQL. Jeśli jest to ustawienie, które użytkownik może zmienić i chcę zapisać wybór do kolejnych uruchomień, utworzę tabelę, która będzie używana jako rejestr i po prostu wyciągam poszczególne wpisy do zmiennych w razie potrzeby.


1

Wiem, że ta odpowiedź została zaakceptowana, ale chciałem opowiedzieć o tym, jak to zrobiliśmy w moim ostatnim sklepie z programistami, w którym staraliśmy się maksymalnie ograniczyć operacje wejścia / wyjścia bazy danych.

Użyliśmy plików dołączanych po stronie serwera dla możliwie największej liczby struktur danych typu wyszukiwania. Służyło to głównie do nawigacji w witrynie (w tym nawigacji podrzędnej), ale wykorzystaliśmy ją również do tylu rozwijanych menu i pól wyboru, jak to możliwe (stany, kraje, kategorie).

Początkowo pobraliśmy wszystkie te dane z bazy danych. Ponieważ daliśmy klientowi widget administratora, mogą oni dowolnie zmieniać te dane i nigdy nie daliśmy się zaskoczyć drobnymi zmianami. Przez większość czasu dane te prawie nigdy się nie zmieniały, ale okazjonalnie by się zmieniały.

Zawsze szukaliśmy szybszych czasów ładowania. Postanowiliśmy więc wdrożyć jak najwięcej statycznych plików tekstowych po stronie serwera, jak to możliwe. Zrobiliśmy to po stronie widgetu administratora. Za każdym razem, gdy aktualizowana jest tabela bazy danych, regenerujemy odpowiedni statyczny plik tekstowy. To zapewniło nam bardzo elastyczne i szybkie środowisko.


0

Moim rozwiązaniem tego problemu, które może nie działać we wszystkich sytuacjach, jest powiązanie statycznych danych z bazy danych z zakodowanym na stałe enum. Ponieważ problem wynika z powiązania danych dynamicznych (bazy danych) z logiką statyczną (kodem), jawnie (i luźno) to powiązanie, mając tabelę bazy danych powiązaną z enum. Dawny:

LooseDBCodeBinding (database table)
   ID : Int32 (key)
   Name : String
   HardCodedTypeID : Int32

// in code:
public enum LooseDBCodeBinding
{
   TYPE_1 = 1,
   TYPE_2 = 2,
   TYPE_3 = 3 // etc...
}

Następnie napisz interfejs użytkownika, który pozwala łatwo przeglądać listę LooseDBCodeBindingrekordów i mapować je na LooseDBCodeBinding enumwartości (w tym obsługę „zepsutych” powiązań). Następnie możesz programować wokół enumi projektować bazę danych wokół klucza tabeli, a tylko ta jedna tabela ma wiedzę na temat obu kontekstów.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.