Najlepsze praktyki stosowania i utrzymywania enum

Widziałem tu kilka pytań/dyskusji na temat najlepszego sposobu obsługi i utrzymywania wartości podobnych do enum (np. Persisting data suited for enums , Jak utrzymać enum używając NHibernate), i chciałbym zapytać, co to jest ogólny consenus.

W szczególności:

  • jak należy traktować te wartości w kodzie?
  • jak powinny być przechowywane w bazie danych (jako tekst/jako liczba)?
  • jakie są kompromisy różnych rozwiązania?

Uwaga: przeniosĺ 'em wyjaĹ" nienia pierwotnie zawarte w tym pytaniu na odpowiedĹş.

Author: sleske, 2009-04-14

10 answers

Zgadzam się z wieloma z tego, co mówisz. Chciałbym jednak dodać jedną rzecz na temat trwałości enum: nie wierzę, że generowanie enum w czasie kompilacji z wartości DB jest dopuszczalne, ale myślę również, że sprawdzenie runtime nie jest dobrym rozwiązaniem. Zdefiniowałbym trzeci środek: mieć test jednostkowy, który sprawdzi wartości enum względem bazy danych. Zapobiega to "przypadkowym" rozbieżnościom i unika narzutu sprawdzania enum z bazą danych za każdym razem, gdy kod jest uruchomiony.

 18
Author: Paul Sonier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-28 20:12:42

Początkowy artykuł wygląda mi dobrze. Mimo to, opierając się na komentarzach, wydaje się, że niektóre uwagi dotyczące enum Javy mogą wyjaśnić kilka rzeczy.

Typ Enum w Javie jest klasą z definicji, ale wielu programistów ma tendencję do zapominania o tym, ponieważ raczej odnoszą go do "listy dozwolonych wartości", jak w niektórych innych językach. To coś więcej.

Tak więc, aby uniknąć tych poleceń switch, rozsądne może być umieszczenie kodu i dodatkowych metod w klasie enum. Jest prawie nigdy nie ma potrzeby tworzenia osobnej "enum-like real class".

Rozważ również punkt dokumentacji - czy chcesz udokumentować rzeczywiste znaczenie swojego enum w bazie danych? W kodzie źródłowym odzwierciedlającym wartości (Twój typ enum) czy w jakiejś zewnętrznej dokumentacji? Ja osobiście wolę kod źródłowy.

Jeśli chcesz przedstawić wartości enum jako liczby całkowite w bazie danych ze względu na szybkość lub z jakiegokolwiek powodu, mapowanie powinno również znajdować się w enum Javy. Dostaniesz string-name domyślne mapowanie i jestem z tego zadowolony. Z każdą wartością enum związana jest liczba porządkowa, ale używanie jej bezpośrednio jako mapowania pomiędzy kodem a bazą danych nie jest zbyt jasne, ponieważ ta liczba porządkowa ulegnie zmianie, jeśli ktoś zmieni kolejność wartości w kodzie źródłowym. Lub dodaje dodatkowe wartości enum pomiędzy istniejącymi wartościami. Lub usuwa jakąś wartość.

(oczywiście, jeśli ktoś zmieni nazwę enum w kodzie źródłowym, domyślne mapowanie łańcuchów też się nie zgadza, ale rzadziej zdarza się to przypadkowo. I możesz łatwiej przed tym chronić, jeśli to konieczne, umieszczając pewne ograniczenia sprawdzania i sprawdzania w bazie danych, jak sugerowano już tutaj. )

 12
Author: lokori,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-28 15:50:39

W obsłudze kodu dla C# przegapiłeś zdefiniowanie delcaringu wartości 0. Zawsze deklaruję swoją pierwszą wartość jako:

public enum SomeEnum
{
    None = 0,
}

Aby służyć jako wartość null. Ponieważ typ kopii zapasowej jest liczbą całkowitą, a liczba całkowita domyślnie wynosi 0, więc jest to ogromnie przydatne w wielu miejscach, aby wiedzieć, czy enum zostało ustawione programowo, czy nie.

 6
Author: Quibblesome,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-23 15:11:12

Java lub C# powinny zawsze używać enum w kodzie. Zastrzeżenie: moim tłem jest C#.

Jeśli wartość ma być utrzymywana w bazie danych, całkowe wartości każdego elementu wyliczenia powinny być wyraźnie zdefiniowane tak, aby późniejsza zmiana w kodzie nie przypadkowo zmieniła przetłumaczonych Wartości wyliczeń, a tym samym zachowania aplikacji.

Wartości powinny być zawsze przechowywane w bazie danych jako wartości całkowe, aby chronić przed refaktoryzacją nazw enum. Prowadzenie dokumentacji każdego wyliczenia w wiki i dodaj komentarz do pola bazy danych wskazującego na stronę wiki dokumentującą Typ. Dodaj również dokumentację XML do typu enum zawierającą link do wpisu wiki, aby była dostępna za pośrednictwem Intellisense.

Jeśli używasz narzędzia do generowania kodu CRUD, powinno ono być w stanie zdefiniować typ wyliczenia, który będzie używany dla kolumny, tak aby generowane obiekty kodu zawsze używały wyliczonych elementów.

Jeśli trzeba zastosować niestandardową logikę dla członka wyliczenia, masz kilka opcje:

  • Jeśli masz enum MyEnum, Utwórz statyczną klasę MyEnumInfo, która oferuje metody użytkowe do odkrywania dodatkowych informacji o członie enum, za pomocą instrukcji switch lub innych niezbędnych środków. Dodanie "Info" na końcu nazwy enum w nazwie klasy gwarantuje, że będą one obok siebie w IntelliSense.
  • Udekoruj elementy wyliczenia atrybutami, aby określić dodatkowe parametry. Na przykład opracowaliśmy EnumDropDown kontrola, która tworzy ASP.NET lista rozwijana wypełniona wartościami wyliczenia i EnumDisplayAttribute określa ładnie sformatowany tekst wyświetlania, który ma być użyty dla każdego elementu.

Nie próbowałem tego, ale z SQL Server 2005 lub nowszym, możesz teoretycznie zarejestrować kod C# z bazą danych, która zawierałaby informacje o enum i możliwość konwersji wartości na enum do użycia w widokach lub innych konstrukcjach, dzięki czemu metoda tłumaczenia danych w sposób łatwiejszy dla baz danych do użyj.

 5
Author: David Boike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-22 17:26:51

próbowałem podsumować moje zrozumienie. Możesz to edytować, jeśli masz jakieś poprawki. Więc zaczyna się:

W kodzie

W kodzie, enums powinny być obsługiwane albo za pomocą natywnego języka enum (przynajmniej w Javie i C#), albo za pomocą czegoś w rodzaju"typesafe enum pattern". Używanie stałych zwykłych (Integer lub podobnych) jest odradzane, ponieważ tracisz bezpieczeństwo typu (i utrudniasz zrozumienie, które wartości są legalnymi danymi wejściowymi dla np. metoda).

Wybór pomiędzy tymi dwoma zależy od tego, ile dodatkowych funkcji ma być dołączone do enum:

  • jeśli chcesz umieścić mnóstwo funkcjonalności w enum (co jest dobre, ponieważ unikasz włączania switch () przez cały czas), klasa jest zwykle bardziej odpowiednia.
  • z drugiej strony, dla prostych wartości enum, enum języka jest zwykle jaśniejsze.

W szczególności, przynajmniej w Javie enum nie może dziedziczyć z innej klasy, więc jeśli masz kilka enum o podobnym zachowaniu, które chcesz umieścić w superklasie, nie możesz używać enum Javy.

Trwające enumery

Aby zapisać liczby, każdej wartości enum należy przypisać unikalny identyfikator. Może to być liczba całkowita lub krótki ciąg znaków. Preferowany jest krótki ciąg znaków, ponieważ może być mnemoniczny (ułatwia DBAs itp. aby zrozumieć surowe dane w db).

  • w oprogramowaniu każdy enum powinien mieć funkcje mapowania do konwersja pomiędzy wartością enum (do użytku wewnątrz oprogramowania) a wartością ID (do utrzymywania się). Niektóre frameworki (np. (N) Hibernate) mają ograniczone wsparcie dla robienia tego automatycznie. W przeciwnym razie musisz umieścić go w enum type / class.
  • baza danych powinna (najlepiej) zawierać tabelę dla każdego enum z listą wartości prawnych. Jedną kolumną będzie ID (patrz wyżej), czyli PK. Dodatkowe kolumny mogą mieć sens np. dla opisu. Wszystkie kolumny tabeli, które będą zawierać wartości z ten enum może następnie użyć tej "tabeli enum" jako FK. Gwarantuje to, że niepoprawne wartości enum nigdy nie zostaną utrzymane i pozwala DB "stać samemu".

Jeden problem z tym podejściem polega na tym, że lista prawnych wartości enum istnieje w dwóch miejscach (kod i baza danych). Jest to trudne do uniknięcia i dlatego często uważane za dopuszczalne, ale istnieją dwie alternatywy:]}

  • przechowuje tylko listę wartości w DB, generuje Typ enum w czasie budowania. Eleganckie, ale oznacza, że do uruchomienia kompilacji wymagane jest połączenie DB, co wydaje się problematyczne.
  • Zdefiniuj listę wartości w kodzie jako autorytatywną. Sprawdzanie wartości w DB w czasie wykonywania (zwykle przy starcie), narzekanie/przerywanie przy niedopasowaniu.
 4
Author: sleske,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:29:49

Przechowywanie wartości tekstowej enum w bazie danych jest mniej preferowane niż przechowywanie liczby całkowitej, ze względu na dodatkową wymaganą przestrzeń i wolniejsze wyszukiwanie. Jest cenny, ponieważ ma więcej znaczenia niż liczba, jednak baza danych służy do przechowywania, a warstwa prezentacji służy do tego, aby rzeczy wyglądały ładnie.

 3
Author: cjk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-14 11:33:59

Cóż, z mojego doświadczenia, używanie enums do czegokolwiek innego niż przekazywanie opcji (jako FLAG) do natychmiastowego wywołania metody, skutkuje switch-ing w pewnym momencie.

  • Jeśli zamierzasz używać enum na całym swoim kodzie, możesz skończyć z kodem, który nie jest tak łatwy w utrzymaniu (niesławne switch oświadczenie)
  • wydłużanie enum jest bólem. Dodajesz nowy element enum i kończysz przeglądając cały kod, aby sprawdzić wszystkie warunki.
  • Z. NET 3.5, można dodaj metody rozszerzeń do enum, aby zachowywały się bardziej jak Klasy. Jednak dodanie prawdziwej funkcjonalności w ten sposób nie jest takie proste, ponieważ nadal nie jest klasą (w metodzie rozszerzenia można by użyć switch-es, jeśli nie gdzie indziej.

Więc dla enum-podobnego podmiotu z nieco większą funkcjonalnością powinieneś poświęcić trochę czasu i utworzyć go jako klasę, mając na uwadze kilka rzeczy:

  • aby Twoja klasa zachowywała się jak enum, możesz albo zmusić każdą pochodną klasę do tworzy instancje jako Singleton lub override Equals, aby umożliwić porównywanie wartości różnych instancji.
  • jeśli twoja klasa jest podobna do enum, powinno to oznaczać, że nie powinna zawierać stanu serializowalnego - deserializacja powinna być możliwa tylko z jej typu(coś w rodzaju "ID", jak powiedziałeś).
  • logika Persistence powinna być ograniczona tylko do klasy bazowej, w przeciwnym razie rozszerzenie twojego "enum" byłoby koszmarem. W przypadku, gdy poszedłeś na wzór Singletona, musisz zapewnić odpowiednie deserializacja do pojedynczych instancji.
 3
Author: Groo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-27 08:07:40

Za każdym razem, gdy odnajdujesz siebie używając "magicznych liczb" w kodzie zmień na enums. Poza tym oszczędność czasu (ponieważ magia zniknie, gdy pojawią się błędy ...) to uratuje twoje oczy i pamięć (znaczące liczby sprawiają, że kod jest bardziej czytelny i samodokumentujący się), ponieważ zgadnij co-najprawdopodobniej jesteś osobą, która utrzymuje i rozwija swój własny kod

 3
Author: Yordan Georgiev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-27 19:31:19

Imho, co do części kodu:

Powinieneś Zawsze używać typu "enum" do wyliczania, w zasadzie otrzymujesz wiele darmowych rzeczy, jeśli to zrobisz: bezpieczeństwo typu, hermetyzacja i unikanie przełączania, wsparcie niektórych kolekcji, takich jak EnumSet i EnumMap oraz przejrzystość kodu.

Jeśli chodzi o część persistence, zawsze możesz utrzymywać reprezentację ciągu enum i ładować ją z powrotem za pomocą enum.metoda valueOf (String).

 2
Author: MahdeTo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-14 11:27:05

Wiem, że to stare forum, co jeśli baza danych może mieć inne rzeczy integrujące się bezpośrednio z nim? Np. gdy wynikowy DB jest jedynym celem kodu. Następnie będziesz definiował liczby przy każdej integracji. Lepiej mieć je w DB. W przeciwnym razie zgadzam się z oryginalnym postem.

 1
Author: Chalky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-05 20:23:49