Załóżmy, że piszesz aplikację, którą może skonfigurować użytkownik. Do przechowywania tych „danych konfiguracyjnych” w bazie danych powszechnie stosuje się dwa wzorce.
Tabeli jednorzędowy
CompanyName | StartFullScreen | RefreshSeconds | ... ---------------+-------------------+------------------+-------- ACME Inc. | true | 20 | ...
Nazwa-wartość-pair stół
ConfigOption | Value -----------------+------------- CompanyName | ACME Inc. StartFullScreen | true (or 1, or Y, ...) RefreshSeconds | 20 ... | ...
Obie opcje widziałem na wolności i obie mają oczywiste zalety i wady, na przykład:
- Tabele jednorzędowe ograniczają liczbę możliwych opcji konfiguracji (ponieważ liczba kolumn w rzędzie jest zwykle ograniczona). Każda dodatkowa opcja konfiguracji wymaga zmiany schematu DB.
- W tabeli par nazwa-wartość wszystko jest „sznurkowo wpisane” (musisz zakodować / zdekodować parametry logiczne / datę / itp.).
- (wiele więcej)
Czy w społeczności programistów istnieje konsensus co do tego, która opcja jest lepsza?
Odpowiedzi:
Osobiście wolę tabele jednorzędowe dla większości rzeczy. Chociaż prawdą jest, że jest mniej elastyczny, chyba że oczekujesz dynamicznego zachowania, w razie potrzeby możesz dodać dodatkowe kolumny później. W pewnym sensie jest to odpowiednik użycia słownika / mapy do przechowywania par nazwa-wartość w porównaniu do posiadania członków klasy podczas programowania. To prawda, że nie jest to idealna metafora, ale wiele zalet i wad jest równoległych, gdy się nad tym zastanowić.
Czy użyłbyś słownika / mapy nad członkami klasy? Prawdopodobnie nie, chyba że masz powód, by sądzić, że ilość danych, które mają być reprezentowane, można w pełni dostosować, podobnie jak w przypadku tabeli par nazwa-wartość.
źródło
Zwykle wybrałbym opcję 2, ALE miałbym wiele kolumn, aby wymusić typ danych
Opcja 1 ma tę dodatkową zaletę, że można bardzo łatwo „zamieniać” całe konfiguracje, dodając
Active
kolumnę.źródło
activatedOn
znacznikiem czasu, abyś wiedział, kiedy został aktywowany. A jeśli wybierzesz opcję 2 ... co się stanie, jeśli w końcu przechowujesz wartości w wielu kolumnach (lub w wyroczni, gdzie (najwyraźniej) null i pusty ciąg są równoważne)?Dla mnie to, czy wybierzesz jednorzędowy czy EAV, zależy od tego, jak chcesz je spożywać.
Moc EAV polega na tym, że można dodawać nowe dane bez zmian w strukturze. Oznacza to, że jeśli chcesz nową wartość konfiguracji, po prostu dodaj ją do tabeli i wyciągnij w żądanym miejscu w kodzie, i nie musisz dodawać nowego pola do domeny, schematu, mapowania, zapytań DAL itd.
Jego wadą jest to, że ma tylko najsłabszą strukturę, co wymaga od ciebie pesymistycznego traktowania danych. Każde użycie dowolnej wartości konfiguracyjnej musi przewidywać, że wartość nie będzie obecna lub nie będzie miała odpowiedniego formatu i będzie zachowywać się odpowiednio, gdy nie będzie. Wartość konfiguracji nie może być przetwarzalna na wartość double, int lub char. Może być zerowy. może nie być wcale wiersza dla wartości. Sposoby obejścia tego zwykle wymagają istnienia pojedynczej prawidłowej wartości „domyślnej” dla wszystkich wartości konfiguracyjnych określonego typu kodu ( wyjątkowo rzadko; częściej wartość domyślna jest tak samo problematyczna przy zużyciu kodu jak żadna) lub prowadzić zakodowany słownik wartości domyślnych (który musi się zmieniać za każdym razem, gdy dodawana jest nowa kolumna, co sprawia, że podstawową zaletą pamięci EAV jest dość dyskusyjny).
Pojedynczy szeroki rząd jest wręcz przeciwny. Odwzorowujesz go na pojedyncze wystąpienie obiektu konfiguracji z polem / właściwością dla każdej istniejącej wartości konfiguracji. Wiesz dokładnie, jakiego typu powinny być te wartości w czasie kompilacji, i „szybko się nie udaje” w DAL, jeśli kolumna konfiguracji nie istnieje lub nie ma wartości odpowiedniego typu, co daje jedno miejsce na wychwytywanie wyjątków w sprawie problemów z odzyskiwaniem konfiguracji / nawadnianiem.
Główną wadą jest to, że dla każdej nowej wartości wymagana jest zmiana strukturalna; nowa kolumna DB, nowa kolumna w DAL (mapowanie lub zapytania SQL / SP), nowa kolumna domeny, wszystkie niezbędne do poprawnego przetestowania użycia.
Właściwą sytuacją do zastosowania któregokolwiek z nich jest sytuacja, w której wady są łagodzone. Dla mnie większość sytuacji związanych z kodowaniem konfiguracji wymaga implementacji jednorzędowej. Wynika to głównie z tego, że jeśli wprowadzasz zupełnie nową wartość konfiguracji, która rządzi zachowaniem jakiejś części twojego programu, musisz już zmienić kod, aby użyć nowej wartości konfiguracji; dlaczego nie wyskoczyć do obiektu config i dodać wartość, która ma być użyta?
Krótko mówiąc, schemat EAV do przechowywania konfiguracji tak naprawdę nie rozwiązuje problemu, który ma rozwiązać, a większość obejść problemów, które przedstawia, narusza DRY.
źródło
Powiedziałbym, że szczególnie w przypadku wartości konfiguracyjnych - przejdź do jednego wiersza. Jak często te kolumny i tak będą się zmieniać, chyba że aktualnie przechodzisz programowanie?
Prawdopodobnie najlepiej zabezpieczyć typ danych wartości niż kod rozszerzalności, którego prawdopodobnie nie będziesz mieć w czasie przestoju między dużymi (r) wydaniami. Poza tym dodanie lub usunięcie pojedynczej kolumny jest najłatwiejszą dostępną migracją. Nie widzę bólu głowy podczas tworzenia nowej opcji konfiguracji.
Ponadto powiedziałeś, że „użytkownicy” mogą konfigurować te opcje bez ograniczenia. Czy są to konfiguracje dla poszczególnych użytkowników? Jeśli tak, będę jeszcze mocniej argumentować, że opcje konfiguracji powinny znajdować się w kolumnach - jeden wiersz na użytkownika. Zaoszczędzi to później wielu problemów związanych z konserwacją.
źródło
Jeśli Twoi klienci mogą przetwarzać fragmenty JSON (to nie tylko tablice i słowniki, ale także zwykłe ciągi, liczby, booleany, wartości null), możesz mieć tabelę z wieloma wierszami z nazwą opcji i wartością ciągu zawierającego JSON. Pozwala to również przechowywać wartości strukturalne, a kod do ich przetwarzania powinien już tam być.
Jeśli Twoi klienci nie mogą przetwarzać fragmentów JSON, zdobądź nowych klientów.
źródło
Jednorzędowe zalety: dobrze zdefiniowane. Minusy: Zmiana konfiguracji może być uciążliwa. Migracje DB itp.
Zalety wartości encji: Super elastyczny, wspiera ewolucję konfiguracji. Minusy: integralność referencyjna? Więcej kontroli w kodzie, aby sprawdzić, czy właściwość istnieje, zanim będziesz mógł cokolwiek na niej zrobić.
Przyjąłbym podejście 2 wspierane przez nierelacyjną bazę danych, taką jak Mongo. Jeśli jest coś, czego możesz być pewien, to zmiana.
źródło
Używać obu!
Posortuj, które opcje mogą mieć wiele instancji i jakie są ogólne.
Tabela jednorzędowa (konfiguracje)
Tabela para nazwa-wartość (opcje)
Myślę, że to jest bardziej elastyczne.
źródło