Best Practices für die Verwendung und Beibehaltung von Aufzählungen

Lesezeit: 9 Minuten

Ich habe hier mehrere Fragen/Diskussionen über die beste Art und Weise gesehen, Enum-ähnliche Werte zu handhaben und beizubehalten (z. B. Persistente Daten, die für Enums geeignet sind, How to persist an enum using NHibernate ), und ich möchte fragen, was der allgemeine Konsens ist .

Im Speziellen:

  • Wie sollen diese Werte im Code behandelt werden?
  • Wie sollen sie in einer Datenbank gespeichert werden (als Text/als Zahl)?
  • Was sind die Kompromisse verschiedener Lösungen?

Hinweis: Ich habe die ursprünglich in dieser Frage enthaltenen Erklärungen in eine Antwort verschoben.

Ich stimme mit vielem von dem überein, was Sie sagen. Eines möchte ich jedoch zur Persistenz von Enums anfügen: Ich glaube nicht, dass die Generierung der Enums zur Build-Zeit aus den DB-Werten akzeptabel ist, aber ich denke auch, dass die Laufzeitprüfung keine gute Lösung ist . Ich würde ein drittes Mittel definieren: Haben Sie einen Komponententest, der die Werte der Aufzählung mit der Datenbank abgleicht. Dies verhindert “zufällige” Abweichungen und vermeidet den Overhead, die Aufzählungen jedes Mal, wenn der Code ausgeführt wird, mit der Datenbank zu vergleichen.

Der ursprüngliche Artikel sieht für mich gut aus. Basierend auf den Kommentaren scheint es jedoch, dass einige Kommentare zu Java-Enumerationen einige Dinge klären könnten.

Der Enum-Typ in Java ist per Definition eine Klasse, aber viele Programmierer neigen dazu, dies zu vergessen, weil sie ihn eher mit einer “Liste zulässiger Werte” in Verbindung bringen, wie in einigen anderen Sprachen. Es ist mehr als das.

Um also diese switch-Anweisungen zu vermeiden, könnte es sinnvoll sein, etwas Code und zusätzliche Methoden in die Enum-Klasse zu packen. Es besteht fast nie die Notwendigkeit, eine separate “Enumerations-ähnliche reale Klasse” zu erstellen.

Denken Sie auch an den Dokumentationspunkt – wollen Sie die eigentliche Bedeutung Ihrer Aufzählung in der Datenbank dokumentieren? Im Quellcode, der die Werte widerspiegelt (Ihr Enum-Typ) oder in einer externen Dokumentation? Ich persönlich bevorzuge den Quellcode.

Wenn Sie Enum-Werte aus Geschwindigkeitsgründen oder aus anderen Gründen als Ganzzahlen in der Datenbank darstellen möchten, sollte sich diese Zuordnung auch in der Java-Enumeration befinden. Standardmäßig erhalten Sie eine Zeichenfolgennamenzuordnung, und damit war ich zufrieden. Jedem Aufzählungswert ist eine Ordnungszahl zugeordnet, aber die direkte Verwendung als Zuordnung zwischen Code und Datenbank ist nicht sehr sinnvoll, da sich diese Ordnungszahl ändert, wenn jemand die Werte im Quellcode neu anordnet. Oder fügt zusätzliche Enum-Werte zwischen vorhandenen Werten hinzu. Oder entfernt einen Wert.

(Wenn jemand den Namen der Aufzählung im Quellcode ändert, geht natürlich auch die Standard-String-Zuordnung schief, aber das passiert weniger wahrscheinlich versehentlich. Und Sie können sich bei Bedarf leichter dagegen schützen, indem Sie eine Laufzeitprüfung durchführen und überprüfen Sie die Einschränkungen in der Datenbank, wie hier bereits vorgeschlagen. )

  • Es gibt zwei Szenarien, die unterstützt werden müssen: jemand, der die Aufzählungen in meiner Datei neu anordnet, ODER jemand, der einige Umgestaltungen durchführt (um schlechte anfängliche Namenswahlen zu klären) und dauerhafte Daten beschädigt. Ich denke, letzteres ist wichtiger, und die Ordnungszahl ist der Weg für die Datenpersistenz.

    – Justin

    12. Mai 2010 um 21:18 Uhr


Ich habe versucht, mein Verständnis zusammenzufassen. Fühlen Sie sich frei, dies zu bearbeiten, wenn Sie Korrekturen haben. Hier geht es also:

Im Code

Im Code sollten Aufzählungen entweder mit dem nativen Aufzählungstyp der Sprache (zumindest in Java und C#) oder mit etwas wie dem “typsicheren Aufzählungsmuster” behandelt werden. Es wird davon abgeraten, einfache Konstanten (Integer oder ähnliches) zu verwenden, da Sie die Typsicherheit verlieren (und es schwierig machen, zu verstehen, welche Werte zulässige Eingaben für zB eine Methode sind).

Die Wahl zwischen diesen beiden hängt davon ab, wie viel zusätzliche Funktionalität an die Aufzählung angehängt werden soll:

  • Wenn Sie eine Menge Funktionalität in die Aufzählung packen möchten (was gut ist, weil Sie vermeiden, ständig switch() zu verwenden), ist eine Klasse normalerweise besser geeignet.
  • Andererseits ist bei einfachen Enum-ähnlichen Werten die Enum der Sprache normalerweise klarer.

Insbesondere kann eine Aufzählung zumindest in Java nicht von einer anderen Klasse erben. Wenn Sie also mehrere Aufzählungen mit ähnlichem Verhalten haben, die Sie in eine Oberklasse einfügen möchten, können Sie die Aufzählungen von Java nicht verwenden.

Bestehende Aufzählungen

Um Aufzählungen dauerhaft zu speichern, sollte jedem Aufzählungswert eine eindeutige ID zugewiesen werden. Dies kann entweder eine Ganzzahl oder eine kurze Zeichenfolge sein. Eine kurze Zeichenfolge wird bevorzugt, da sie mnemonisch sein kann (erleichtert es DBAs usw., die Rohdaten in der Datenbank zu verstehen).

  • In der Software sollte jede Aufzählung dann über Mapping-Funktionen verfügen, um zwischen der Aufzählung (zur Verwendung innerhalb der Software) und dem ID-Wert (zur Persistenz) umzuwandeln. Einige Frameworks (z. B. (N)Hibernate) unterstützen dies nur begrenzt automatisch. Andernfalls müssen Sie es in den Enum-Typ/die Klasse einfügen.
  • Die Datenbank sollte (idealerweise) eine Tabelle für jede Aufzählung enthalten, die die zulässigen Werte auflistet. Eine Spalte wäre die ID (siehe oben), die die PK ist. Zusätzliche Spalten können zB für eine Beschreibung sinnvoll sein. Alle Tabellenspalten, die Werte aus dieser Aufzählung enthalten, können dann diese “Aufzählungstabelle” als FK verwenden. Dies garantiert, dass niemals falsche Enum-Werte persistiert werden können, und ermöglicht dem DB, „für sich selbst zu stehen“.

Ein Problem bei diesem Ansatz besteht darin, dass die Liste der zulässigen Enum-Werte an zwei Stellen vorhanden ist (Code und Datenbank). Dies ist schwer zu vermeiden und wird daher oft als akzeptabel angesehen, aber es gibt zwei Alternativen:

  • Behalten Sie nur die Werteliste in der DB, generieren Sie den Enum-Typ zur Build-Zeit. Elegant, bedeutet aber, dass eine DB-Verbindung erforderlich ist, damit ein Build ausgeführt werden kann, was problematisch erscheint.
  • Definieren Sie die Werteliste im Code als autoritativ. Zur Laufzeit (normalerweise beim Start) mit den Werten in der DB vergleichen, bei Nichtübereinstimmung beschweren/abbrechen.

Bei der Codebehandlung für C# haben Sie es versäumt, den Wert 0 zu löschen. Ich deklariere fast immer meinen ersten Wert als:

public enum SomeEnum
{
    None = 0,
}

Um als Nullwert zu dienen. Da der Sicherungstyp eine Ganzzahl ist und eine Ganzzahl standardmäßig auf 0 eingestellt ist, ist es an vielen Stellen äußerst nützlich zu wissen, ob eine Aufzählung tatsächlich programmgesteuert festgelegt wurde oder nicht.

Java oder C# sollten immer Enums im Code verwenden. Haftungsausschluss: Mein Hintergrund ist C#.

Wenn der Wert in einer Datenbank gespeichert werden soll, sollten die ganzzahligen Werte jedes Aufzählungsmitglieds explizit definiert werden, damit eine spätere Codeänderung nicht versehentlich übersetzte Aufzählungswerte und damit das Anwendungsverhalten ändert.

Werte sollten immer als integrale Werte in einer Datenbank gespeichert werden, um sie vor der Umgestaltung von Aufzählungsnamen zu schützen. Bewahren Sie die Dokumentation zu jeder Aufzählung in einem Wiki auf und fügen Sie einen Kommentar zum Datenbankfeld hinzu, der auf die Wiki-Seite verweist, die den Typ dokumentiert. Fügen Sie dem Aufzählungstyp auch eine XML-Dokumentation hinzu, die einen Link zum Wiki-Eintrag enthält, damit er über Intellisense verfügbar ist.

Wenn Sie ein Tool zum Generieren von CRUD-Code verwenden, sollte es in der Lage sein, einen Aufzählungstyp zu definieren, der für eine Spalte verwendet werden soll, sodass generierte Codeobjekte immer Aufzählungselemente verwenden.

Wenn für ein Enumerationsmitglied eine benutzerdefinierte Logik angewendet werden muss, haben Sie einige Optionen:

  • Wenn Sie eine Aufzählung MyEnum haben, erstellen Sie eine statische Klasse MyEnumInfo, die Dienstprogrammmethoden anbietet, um zusätzliche Informationen über das Aufzählungsmitglied durch Switch-Anweisungen oder andere erforderliche Mittel zu ermitteln. Das Anhängen von „Info“ an das Ende des Aufzählungsnamens im Klassennamen stellt sicher, dass sie in IntelliSense nebeneinander stehen.
  • Dekorieren Sie die Enumerationsmitglieder mit Attributen, um zusätzliche Parameter anzugeben. Zum Beispiel haben wir ein EnumDropDown-Steuerelement entwickelt, das ein mit Aufzählungswerten gefülltes ASP.NET-Dropdown erstellt, und ein EnumDisplayAttribute gibt den schön formatierten Anzeigetext an, der für jedes Mitglied verwendet werden soll.

Ich habe dies nicht versucht, aber mit SQL Server 2005 oder höher könnten Sie theoretisch C#-Code in der Datenbank registrieren, der Aufzählungsinformationen und die Möglichkeit zum Konvertieren von Werten in Aufzählungen zur Verwendung in Ansichten oder anderen Konstrukten enthalten würde, wodurch eine Methode zum Übersetzen der Daten auf eine Weise, die für DBAs einfacher zu verwenden ist.

  • +1 Das explizite Zuweisen von Werten ist die einzige Möglichkeit, “Korruption” zu vermeiden, wenn Sie die Aufzählung ändern

    – Asche999

    20. Dezember 2012 um 17:34 Uhr

Imho, was den Codeteil betrifft:

Du solltest stets Verwenden Sie den Typ ‘enum’ für Ihre Aufzählungen, im Grunde erhalten Sie eine Menge Werbegeschenke, wenn Sie dies tun: Typsicherheit, Kapselung und Vermeidung von Schaltern, die Unterstützung einiger Sammlungen wie z EnumSet und EnumMap und Codeklarheit.

Was den Persistenzteil betrifft, können Sie die Zeichenfolgendarstellung der Aufzählung immer beibehalten und mit der Methode enum.valueOf(String) zurückladen.

  • +1 Das explizite Zuweisen von Werten ist die einzige Möglichkeit, “Korruption” zu vermeiden, wenn Sie die Aufzählung ändern

    – Asche999

    20. Dezember 2012 um 17:34 Uhr

Das Speichern des Textwerts einer Aufzählung in einer Datenbank ist aufgrund des zusätzlichen Speicherplatzbedarfs und der langsameren Suche weniger bevorzugt als das Speichern einer Ganzzahl. Es ist insofern wertvoll, als es mehr Bedeutung hat als eine Zahl, aber die Datenbank dient der Speicherung und die Präsentationsschicht dient dazu, die Dinge schön aussehen zu lassen.

  • Es ist nicht garantiert, dass der int-Wert der Aufzählung im Laufe der Zeit gleich bleibt.

    – Miguel Ping

    14. April 2009 um 11:43 Uhr

  • Auch wenn Sie eine kurze Saite verwenden, sollte die Leistung gleich sein. Ein char(2) benötigt 2 Bytes, ein int normalerweise auch 2 oder 4.

    – schleske

    14. April 2009 um 11:44 Uhr

  • @Miguel Ping: Die Idee ist ausdrücklich Zuweisen einer ID (int oder char) zu jeder Aufzählung. Die Verwendung des intern generierten int des Enums ist in der Tat sehr gefährlich.

    – schleske

    14. April 2009 um 11:47 Uhr

  • Wenn in der DB eine Bedeutung über ganzzahlige Werte hinaus gewünscht wird, würde ich eine Tabelle verwenden, die die ganzzahligen Werte auf für Menschen lesbare Zeichenfolgen abbildet. auch ja, die Integer-Werte dürfen sich später nicht mehr ändern. sollte aber kein Problem sein; Die einzige Bedeutung, die zugrunde liegende Aufzählungs-Ganzzahlwerte haben sollten, besteht darin, dass sie sich von den anderen Mitgliedern der Aufzählung unterscheiden. (dh: sie sollten keinen Grund haben, sich jemals zu ändern). wenn die ganzzahligen Werte eine Bedeutung haben, die über die eindeutige Identifizierung hinausgeht, sollte wahrscheinlich eine andere Datenstruktur verwendet werden.

    – David Cousineau

    3. Januar 2012 um 21:17 Uhr

1205030cookie-checkBest Practices für die Verwendung und Beibehaltung von Aufzählungen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy