Was ist der beste Weg, um Aufzählungen in einer Datenbank zu speichern?
Ich weiß, dass Java Methoden name()
und valueOf()
Methoden zum Konvertieren von Enum-Werten in einen String und zurück bereitstellt . Aber gibt es noch andere (flexible) Optionen zum Speichern dieser Werte?
Gibt es eine clevere Möglichkeit, Aufzählungen in eindeutige Zahlen umzuwandeln ( ordinal()
ist nicht sicher zu verwenden)?
Aktualisieren:
Vielen Dank für alle tollen und schnellen Antworten! Es war wie ich vermutet hatte.
Allerdings ein Hinweis zum 'Toolkit'; Das ist eine Möglichkeit. Das Problem ist, dass ich jedem von mir erstellten Aufzählungstyp die gleichen Methoden hinzufügen müsste. Das ist viel duplizierter Code und im Moment unterstützt Java keine Lösungen dafür (eine Java-Aufzählung kann andere Klassen nicht erweitern).
Antworten:
Wir speichern Aufzählungen nie mehr als numerische Ordnungswerte. es macht das Debuggen und die Unterstützung viel zu schwierig. Wir speichern den tatsächlichen Aufzählungswert, der in eine Zeichenfolge konvertiert wurde:
und dann zurücklesen mit:
Das Problem bestand in der Vergangenheit darin, Enterprise Manager anzustarren und zu entschlüsseln:
Verse
Letzteres ist viel einfacher. Ersteres erforderte das Aufrufen des Quellcodes und das Finden der numerischen Werte, die den Aufzählungselementen zugewiesen wurden.
Ja, es nimmt mehr Platz in Anspruch, aber die Namen der Aufzählungsmitglieder sind kurz und die Festplatten sind billig, und es lohnt sich viel mehr, bei Problemen zu helfen.
Wenn Sie numerische Werte verwenden, sind Sie außerdem an diese gebunden. Sie können die Elemente nicht gut einfügen oder neu anordnen, ohne die alten Zahlenwerte erzwingen zu müssen. Ändern Sie beispielsweise die Anzugaufzählung in:
müsste werden:
um die in der Datenbank gespeicherten alten numerischen Werte beizubehalten.
So sortieren Sie sie in der Datenbank
Die Frage kommt auf: Nehmen wir an, ich wollte die Werte bestellen. Einige Leute möchten sie möglicherweise nach dem Ordnungswert der Aufzählung sortieren. Natürlich ist es bedeutungslos, die Karten nach dem numerischen Wert der Aufzählung zu ordnen:
Das ist nicht die Reihenfolge, die wir wollen - wir wollen sie in Aufzählungsreihenfolge:
Die gleiche Arbeit, die zum Speichern von Ganzzahlwerten erforderlich ist, ist zum Speichern von Zeichenfolgen erforderlich:
Aber das ist nicht die Reihenfolge, die wir wollen - wir wollen sie in Aufzählungsreihenfolge:
Meiner Meinung nach gehört diese Art von Ranking in die Benutzeroberfläche. Wenn Sie Elemente nach ihrem Aufzählungswert sortieren: Sie machen etwas falsch.
Aber wenn Sie das wirklich tun wollten, würde ich eine
Suits
Dimensionstabelle erstellen :Wenn Sie Ihre Karten ändern möchten, um Kissing Kings New Deck Order zu verwenden , können Sie sie auf diese Weise zu Anzeigezwecken ändern, ohne alle Ihre Daten wegzuwerfen:
Jetzt trennen wir ein internes Programmierdetail (Aufzählungsname, Aufzählungswert) mit einer Anzeigeeinstellung, die für Benutzer bestimmt ist:
quelle
12.37 ms
stattdessen dauert12.3702 ms
. Das meine ich mit "im Lärm" . Sie führen die Abfrage erneut aus und es dauert13.29 ms
, oder11.36 ms
. Mit anderen Worten, die Zufälligkeit des Thread-Schedulers wird jede theoretische Mikrooptimierung, die für niemanden in irgendeiner Weise sichtbar ist, drastisch überschwemmen.Sofern Sie keine besonderen Leistungsgründe haben, um dies zu vermeiden, würde ich empfehlen, eine separate Tabelle für die Aufzählung zu verwenden. Verwenden Sie die Fremdschlüsselintegrität, es sei denn, die zusätzliche Suche bringt Sie wirklich um.
Anzugstabelle:
Spielertisch
suit_id
) sind unabhängig von Ihrem Aufzählungswert, sodass Sie auch Daten aus anderen Sprachen bearbeiten können.quelle
public enum foo {bar}
als auchCREATE TABLE foo (name varchar);
das kann leicht aus der Synchronisation geraten.Ich würde argumentieren, dass der einzig sichere Mechanismus hier darin besteht, den String-
name()
Wert zu verwenden. Wenn Sie mit dem DB Schreiben Sie könnten einen sproc , um den Wert zu setzen und beim Lesen eine Ansicht verwenden. Auf diese Weise gibt es, wenn sich die Aufzählungen ändern, eine Indirektionsebene in der Sproc / Ansicht, um die Daten als Aufzählungswert darstellen zu können, ohne dies der DB "aufzuzwingen".quelle
Wie Sie sagen, ist Ordnungszahl ein bisschen riskant. Betrachten Sie zum Beispiel:
Wenn Sie dies als Ordnungszahlen gespeichert haben, haben Sie möglicherweise Zeilen wie:
Aber was passiert, wenn Sie Boolean aktualisiert haben?
Dies bedeutet, dass alle Ihre Lügen als "Datei nicht gefunden" falsch interpretiert werden.
Verwenden Sie besser nur eine Zeichenfolgendarstellung
quelle
Bei einer großen Datenbank zögere ich, die Größen- und Geschwindigkeitsvorteile der numerischen Darstellung zu verlieren. Am Ende habe ich oft eine Datenbanktabelle, die die Aufzählung darstellt.
Sie können die Datenbankkonsistenz erzwingen, indem Sie einen Fremdschlüssel deklarieren. In einigen Fällen ist es jedoch möglicherweise besser, diesen nicht als Fremdschlüsseleinschränkung zu deklarieren, was bei jeder Transaktion Kosten verursacht. Sie können die Konsistenz sicherstellen, indem Sie zu Zeiten Ihrer Wahl regelmäßig Folgendes überprüfen:
Die andere Hälfte dieser Lösung besteht darin, einen Testcode zu schreiben, der überprüft, ob die Java-Aufzählung und die Datenbankaufzählungstabelle denselben Inhalt haben. Das bleibt als Übung für den Leser.
quelle
enumID
ist vier Bytes, also haben Sie zusätzliche drei Bytes pro Zeile, indem Sie Namen verwenden. 3 Bytes x 1 Million Zeilen sind 3 MB.enumId
passt sicherlich in zwei Bytes (längere Aufzählungen sind in Java nicht möglich) und die meisten passen in ein einzelnes Byte (was einige DB unterstützen). Der eingesparte Platz ist vernachlässigbar, aber der schnellere Vergleich und die feste Länge sollten helfen.Wir speichern nur den Namen der Aufzählung selbst - er ist besser lesbar.
Wir haben mit dem Speichern bestimmter Werte für Aufzählungen herumgespielt, bei denen es nur eine begrenzte Anzahl von Werten gibt, z. B. diese Aufzählung mit einer begrenzten Anzahl von Status, für deren Darstellung wir ein Zeichen verwenden (aussagekräftiger als ein numerischer Wert):
und wenn Sie viele Werte haben, müssen Sie eine Map in Ihrer Aufzählung haben, um diese getFromXYZ-Methode klein zu halten.
quelle
Wenn Sie Aufzählungen als Zeichenfolgen in der Datenbank speichern, können Sie Dienstprogrammmethoden erstellen, um jede Aufzählung (zu) serialisieren:
quelle
Alle meine Erfahrungen zeigen mir, dass der sicherste Weg, Enums überall beizubehalten, darin besteht, zusätzlichen Codewert oder eine zusätzliche ID zu verwenden (eine Art Weiterentwicklung der @ jeebee-Antwort). Dies könnte ein schönes Beispiel für eine Idee sein:
Jetzt können Sie mit jeder Persistenz fortfahren, die Ihre Enum-Konstanten anhand ihres Codes referenziert. Selbst wenn Sie sich entscheiden, einige konstante Namen zu ändern, können Sie immer den Codewert speichern (z. B.
DWARF("dwarf")
bisGNOME("dwarf")
).Ok, tauchen Sie mit dieser Konzeption etwas tiefer ein. Hier ist eine Dienstprogrammmethode, mit der Sie einen beliebigen Aufzählungswert finden können. Lassen Sie uns jedoch zunächst unseren Ansatz erweitern.
Und lassen Sie unsere Aufzählung es umsetzen:
Dies ist die Zeit für die magische Suchmethode:
Und benutze es wie einen Zauber:
Race race = resolveByCode(Race.class, "elf")
quelle
Ich habe das gleiche Problem, bei dem mein Ziel darin besteht, den Enum-String-Wert anstelle des Ordnungswerts in der Datenbank beizubehalten.
Um dieses Problem zu lösen, habe ich verwendet
@Enumerated(EnumType.STRING)
lösen und mein Ziel wurde gelöst.Zum Beispiel haben Sie eine
Enum
Klasse:Definieren Sie in der Entitätsklasse
@Enumerated(EnumType.STRING)
:Während Sie versuchen, Ihren Wert auf "Datenbank" zu setzen, wird der Wert "Zeichenfolge" als "
APPLE
", "ORANGE
" oder "LEMON
" in der Datenbank beibehalten .quelle
Mehrere Werte mit ODER-Beziehung für ein Aufzählungsfeld. Das Konzept für .NET mit dem Speichern von Aufzählungstypen in einer Datenbank wie einem Byte oder einem Int und der Verwendung von FlagsAttribute in Ihrem Code.
http://blogs.msdn.com/b/efdesign/archive/2011/06/29/enumeration-support-in-entity-framework.aspx
quelle
Sie können einen zusätzlichen Wert in der Aufzählungskonstante verwenden, der sowohl Namensänderungen als auch das erneute Aufrufen der Aufzählungen überlebt:
So erhalten Sie die ID aus der Aufzählung:
So erhalten Sie die Aufzählung von einer ID:
Ich schlage vor, Werte ohne Bedeutung zu verwenden, um Verwirrung zu vermeiden, wenn die Aufzählungsnamen geändert werden müssen.
Im obigen Beispiel habe ich eine Variante der "Grundlegenden Zeilennummerierung" verwendet, bei der Leerzeichen verbleiben, damit die Zahlen wahrscheinlich in derselben Reihenfolge wie die Aufzählungen bleiben.
Diese Version ist schneller als die Verwendung einer sekundären Tabelle, macht das System jedoch stärker von Code- und Quellcode-Kenntnissen abhängig.
Um dies zu beheben, können Sie auch eine Tabelle mit den Enum-IDs in der Datenbank einrichten. Oder gehen Sie in die andere Richtung und wählen Sie IDs für die Aufzählungen aus einer Tabelle aus, während Sie Zeilen hinzufügen.
Nebenbemerkung : Stellen Sie immer sicher , dass Sie nichts entwerfen, das in einer Datenbanktabelle gespeichert und als reguläres Objekt verwaltet werden soll. Wenn Sie sich vorstellen können, dass Sie der Enumeration zu diesem Zeitpunkt beim Einrichten neue Konstanten hinzufügen müssen, ist dies ein Hinweis darauf, dass Sie möglicherweise besser dran sind, stattdessen ein reguläres Objekt und eine Tabelle zu erstellen.
quelle