it-swarm.com.de

Warum sollten Sie eine Aufzählung in der Datenbank speichern?

Ich habe eine Reihe von Fragen gesehen, wie this , in denen um Rat gefragt wurde, wie Aufzählungen in DB gespeichert werden. Aber ich frage mich , warum Sie das tun würden. Nehmen wir also an, ich habe eine Entität Person mit einem gender Feld und einer Gender Aufzählung. Dann hat meine Personentabelle ein Spaltengeschlecht.

Abgesehen von dem offensichtlichen Grund für die Durchsetzung der Korrektheit verstehe ich nicht, warum ich eine zusätzliche Tabelle gender erstellen würde, um das abzubilden, was ich bereits in meiner Anwendung habe. Und ich mag diese Vervielfältigung nicht wirklich.

71
user3748908

Nehmen wir ein anderes Beispiel, das weniger mit Vorstellungen und Erwartungen behaftet ist. Ich habe hier eine Aufzählung, und es sind die Prioritäten für einen Fehler.

Welchen Wert speichern Sie in der Datenbank?

Ich könnte also 'C', 'H', 'M' Und 'L' In der Datenbank speichern. Oder 'HIGH' Und so weiter. Dies hat das Problem von streng typisierten Daten. Es gibt einen bekannten Satz gültiger Werte, und wenn Sie diesen Satz nicht in der Datenbank speichern, kann es schwierig sein, damit zu arbeiten.

Warum speichern Sie die Daten im Code?

Sie haben List<String> priorities = {'CRITICAL', 'HIGH', 'MEDIUM', 'LOW'}; Oder etwas in diesem Sinne im Code. Dies bedeutet, dass Sie verschiedene Zuordnungen dieser Daten zum richtigen Format haben (Sie fügen alle Großbuchstaben in die Datenbank ein, zeigen sie jedoch als Critical an). Ihr Code ist jetzt auch schwer zu lokalisieren. Sie haben die Datenbankdarstellung der Idee an eine Zeichenfolge gebunden, die im Code gespeichert ist.

Überall dort, wo Sie auf diese Liste zugreifen müssen, benötigen Sie entweder eine Codeduplizierung oder eine Klasse mit einer Reihe von Konstanten. Beides ist keine gute Option. Man sollte auch nicht vergessen, dass es andere Anwendungen gibt, die diese Daten verwenden können (die in anderen Sprachen geschrieben sein können - das Java In der Webanwendung wird ein Crystal Reports Berichtssystem verwendet und ein Perl Batch-Job, der Daten einspeist. Die Berichts-Engine muss die gültige Liste der Daten kennen (was passiert, wenn in der Priorität 'LOW' Nichts markiert ist und Sie wissen müssen, dass dies eine gültige Priorität für den Bericht ist?) Und der Stapeljob hätte die Informationen über die gültigen Werte.

Hypothetisch könnten Sie sagen "Wir sind ein einsprachiger Shop - alles ist in Java geschrieben" und eine einzige .jar haben, die diese Informationen enthält - Jetzt bedeutet dies, dass Ihre Anwendungen eng miteinander verbunden sind und dass .jar die Daten enthält. Sie müssen den Berichtsteil und den Stapelaktualisierungsteil zusammen mit der Webanwendung jedes Mal freigeben, wenn sich etwas ändert - und hoffen , dass diese Freigabe erfolgt reibungslos für alle Teile.

Was passiert, wenn Ihr Chef eine andere Priorität wünscht?

Ihr Chef ist heute vorbeigekommen. Es gibt eine neue Priorität - CEO. Jetzt müssen Sie den gesamten Code ändern und neu kompilieren und erneut bereitstellen.

Mit einem "Enum-in-the-Table" -Ansatz aktualisieren Sie die Enum-Liste, um eine neue Priorität zu erhalten. Der gesamte Code, der die Liste erhält, zieht sie aus der Datenbank.

Daten stehen selten alleine da

Bei Prioritäten werden die Datenschlüssel in anderen Tabellen gespeichert, die möglicherweise Informationen zu Workflows enthalten oder die diese Priorität festlegen können oder so weiter.

Zurück zum Geschlecht, wie in der Frage ein wenig erwähnt: Das Geschlecht hat einen Link zu den verwendeten Pronomen: he/his/him Und she/hers/her ... und Sie möchten vermeiden, dass dies in die Code selbst. Und dann kommt Ihr Chef vorbei und Sie müssen hinzufügen, dass Sie das Geschlecht 'OTHER' Haben (um es einfach zu halten) und Sie brauchen um dieses Geschlecht mit they/their/them in Beziehung zu setzen ... und dein Chef sieht, was Facebook hat und ... na ja.

Indem Sie sich auf ein streng typisiertes Datenbit anstatt auf eine Aufzählungstabelle beschränken, müssen Sie diese Zeichenfolge jetzt in einer Reihe anderer Tabellen replizieren, um diese Beziehung zwischen den Daten und ihren anderen Bits aufrechtzuerhalten.

Was ist mit anderen Datenspeichern?

Egal wo Sie dies speichern, es gibt das gleiche Prinzip.

  • Sie könnten eine Datei priorities.prop Haben, die die Liste der Prioritäten enthält. Sie lesen diese Liste aus einer Eigenschaftendatei ein.
  • Sie könnten eine Dokumentenspeicherdatenbank (wie CouchDB ) haben, die einen Eintrag für enums enthält (und dann eine Validierungsfunktion in JavaScript schreiben ):

    {
       "_id": "c18b0756c3c08d8fceb5bcddd60006f4",
       "_rev": "1-c89f76e36b740e9b899a4bffab44e1c2",
       "priorities": [ "critical", "high", "medium", "low" ],
       "severities": [ "blocker", "bad", "annoying", "cosmetic" ]
    }
    
  • Sie könnten eine XML-Datei mit einem kleinen Schema haben:

    <xs:element name="priority" type="priorityType"/>
    
    <xs:simpleType name="priorityType">
      <xs:restriction base="xs:string">
        <xs:enumeration value="critical"/>
        <xs:enumeration value="high"/>
        <xs:enumeration value="medium"/>
        <xs:enumeration value="low"/>
      </xs:restriction>
    </xs:simpleType>
    

Die Kernidee ist dieselbe. Im Datenspeicher selbst muss die Liste der gültigen Werte gespeichert und erzwungen werden. Wenn Sie es hier platzieren, ist es einfacher, über den Code und die Daten nachzudenken. Sie müssen sich nicht darum kümmern, jedes Mal defensiv zu überprüfen, was Sie haben (ist es Großbuchstaben? Oder Kleinbuchstaben? Warum gibt es in dieser Spalte einen chritical -Typ? Usw. ...), weil Sie wissen, was Sie sind Das Zurückkehren aus dem Datenspeicher ist genau das, was der Datenspeicher von Ihnen erwartet - und Sie können den Datenspeicher nach einer Liste gültiger Werte abfragen.

Das wegnehmen

Die Menge der gültigen Werte sind Daten , kein Code. Sie müssen nach TROCKENEM Code streben - aber das Problem der Duplizierung ist dass Sie die Daten im Code duplizieren, anstatt ihren Platz als Daten zu respektieren und in einer Datenbank zu speichern.

Es erleichtert das Schreiben mehrerer Anwendungen für den Datenspeicher und vermeidet Fälle, in denen Sie alles bereitstellen müssen, was eng mit den Daten selbst verbunden ist - weil Sie nicht Ihren Code mit den Daten gekoppelt.

Dies erleichtert das Testen von Anwendungen, da Sie nicht die gesamte Anwendung erneut testen müssen, wenn die Priorität CEO hinzugefügt wird, da Sie keinen Code haben, der sich um den tatsächlichen Wert der Priorität kümmert.

Die Möglichkeit, unabhängig voneinander über den Code und die Daten nachzudenken, erleichtert das Auffinden und Beheben von Fehlern bei der Wartung.

77
user40980

Welche davon führt Ihrer Meinung nach beim Lesen der Abfrage eher zu Fehlern?

select * 
from Person 
where Gender = 1

Oder

select * 
from Person join Gender on Person.Gender = Gender.GenderId
where Gender.Label = "Female" 

Benutzer erstellen Aufzählungstabellen in SQL, weil sie feststellen, dass letztere besser lesbar sind - was zu weniger Fehlern beim Schreiben und Verwalten von SQL führt.

Sie könnten das Geschlecht direkt in Person zu einem String machen, aber dann müssten Sie versuchen, den Fall durchzusetzen. Sie können auch den Speichertreffer für die Tabelle und die Abfragezeit aufgrund des Unterschieds zwischen Zeichenfolgen und Ganzzahlen erhöhen, je nachdem, wie großartig Ihre Datenbank bei der Optimierung von Dingen ist.

21
Telastyn

Ich kann nicht glauben, dass die Leute das noch nicht erwähnt haben.

Fremde Schlüssel

Indem Sie die Aufzählung in Ihrer Datenbank behalten und der Tabelle einen Fremdschlüssel hinzufügen, der einen Aufzählungswert enthält, stellen Sie sicher, dass kein Code jemals falsche Werte für diese Spalte eingibt. Dies hilft Ihrer Datenintegrität und ist der offensichtlichste Grund, warum Sie IMO Tabellen für Aufzählungen haben sollten.

13

Ich bin in dem Lager, das dir zustimmt. Wenn Sie eine Gender-Aufzählung in Ihrem Code und einen tblGender in Ihrer Datenbank behalten, kann es zu Problemen bei der Wartung kommen. Sie müssen dokumentieren, dass diese beiden Entitäten dieselben Werte haben sollten, und daher müssen alle Änderungen, die Sie an einer vornehmen, auch an der anderen vorgenommen werden.

Anschließend müssen Sie die Aufzählungswerte wie folgt an Ihre gespeicherten Prozeduren übergeben:

create stored procedure InsertPerson @name varchar, @gender int
    insert into tblPeople (name, gender)
    values (@name, @gender)

Aber überlegen Sie, wie Sie dies tun würden, wenn Sie diese Werte in einer Datenbanktabelle behalten würden:

create stored procedure InsertPerson @name varchar, @genderName varchar
    insert into tblPeople (name, gender)
    select @name, fkGender
    from tblGender
    where genderName = @genderName --I hope these are the same

Sicher, relationale Datenbanken werden mit Blick auf Joins erstellt, aber welche Abfrage ist leichter zu lesen?


Hier ist eine weitere Beispielabfrage:

create stored procedure SpGetGenderCounts
    select count(*) as count, gender
    from tblPeople
    group by gender

Vergleichen Sie das damit:

create stored procedure SpGetGenderCounts
    select count(*) as count, genderName
    from tblPeople
    inner join tblGender on pkGender = fkGender
    group by genderName --assuming no two genders have the same name

Hier ist noch eine weitere Beispielabfrage:

create stored procedure GetAllPeople
    select name, gender
    from tblPeople

Beachten Sie, dass Sie in diesem Beispiel die Geschlechtszelle in Ihren Ergebnissen von einem int in eine Aufzählung konvertieren müssen. Diese Konvertierungen sind jedoch einfach. Vergleichen Sie das damit:

create stored procedure GetAllPeople
    select name, genderName
    from tblPeople
    inner join tblGender on pkGender = fkGender

Alle diese Abfragen sind kleiner und wartbarer, wenn Sie die Idee haben, die Aufzählungsdefinitionen aus der Datenbank herauszuhalten.

7
user2023861

Ich würde eine Genders-Tabelle erstellen, weil sie für die Datenanalyse verwendet werden kann. Ich könnte alle männlichen oder weiblichen Personen in der Datenbank nachschlagen, um einen Bericht zu erstellen. Je mehr Möglichkeiten Sie haben, Ihre Daten anzuzeigen, desto einfacher ist es, Trendinformationen zu ermitteln. Dies ist natürlich eine sehr einfache Aufzählung, aber bei komplexen Aufzählungen (wie den Ländern der Welt oder Staaten) ist es einfacher, spezielle Berichte zu erstellen.

1
zackery.fix

Wenn Sie über eine Code-Aufzählung verfügen, mit der die Geschäftslogik im Code gesteuert wird, sollten Sie aus den oben/unten beschriebenen Gründen dennoch eine Tabelle erstellen, um die Daten in der Datenbank darzustellen. Hier einige Tipps, um sicherzustellen, dass Ihre DB-Werte mit den Codewerten synchron bleiben:

  1. Machen Sie das ID-Feld in der Tabelle nicht zu einer Identitätsspalte. ID und Beschreibung als Felder einschließen.

  2. Führen Sie in der Tabelle etwas anderes aus, damit Entwickler erkennen, dass die Werte semistatisch/an eine Code-Aufzählung gebunden sind. In allen anderen Nachschlagetabellen (normalerweise, in denen Benutzer Werte hinzufügen können) habe ich normalerweise LastChangedDateTime und LastChangedBy, aber wenn ich sie nicht in enumbezogenen Tabellen habe, kann ich mich daran erinnern, dass sie nur von Entwicklern geändert werden können. Dokumentieren Sie dies.

  3. Erstellen Sie einen Bestätigungscode, der überprüft, ob sich jeder Wert in der Aufzählung in der entsprechenden Tabelle befindet und ob sich nur diese Werte in der entsprechenden Tabelle befinden. Wenn Sie automatisierte "Gesundheitstests" für Anwendungen haben, die nach dem Build ausgeführt werden, finden Sie diese dort. Wenn nicht, lassen Sie den Code beim Start der Anwendung automatisch ausführen, wenn die Anwendung in der IDE ausgeführt wird.

  4. Erstellen Sie die Produktion und liefern Sie SQL-Skripte, die dasselbe tun, jedoch aus der Datenbank heraus. Bei korrekter Erstellung helfen sie auch bei Umgebungsmigrationen.

1
Paul Schirf

Zunächst müssen Sie entscheiden, ob die Datenbank immer nur von einer Anwendung verwendet wird oder ob möglicherweise mehrere Anwendungen sie verwenden können. In einigen Fällen ist eine Datenbank nichts anderes als ein Dateiformat für eine Anwendung (SQLite-Datenbanken können in dieser Hinsicht häufig verwendet werden). In diesem Fall kann ein Bit, das die Aufzählungsdefinition als Tabelle dupliziert, oft in Ordnung und sinnvoller sein.

Sobald Sie jedoch die Möglichkeit in Betracht ziehen möchten, dass mehrere Anwendungen auf die Datenbank zugreifen, ist eine Tabelle für die Aufzählung sehr sinnvoll (die anderen Antworten gehen detaillierter auf das Warum ein). Die andere zu berücksichtigende Sache ist, dass Sie oder ein anderer Entwickler die Rohdaten der Datenbank betrachten möchten. In diesem Fall kann dies als eine andere Anwendungsverwendung angesehen werden (nur eine, bei der das Labormessgerät Raw-SQL ist).

Wenn Sie die im Code definierte Aufzählung (zur Überprüfung des saubereren Codes und der Kompilierungszeit) sowie eine Tabelle in der Datenbank haben, würde ich empfehlen, Komponententests hinzuzufügen, um zu überprüfen, ob die beiden synchron sind.

1
Eric Johnson

Kommt auch darauf an, wer auf die Daten zugreift. Wenn Sie nur eine Anwendung haben, ist dies möglicherweise in Ordnung. Wenn Sie ein Data Warehouse oder ein Berichtssystem hinzufügen. Sie müssen wissen, was dieser Code bedeutet und was die vom Menschen redigierbare Version des Codes ist.

Normalerweise wird die Typentabelle nicht als Aufzählung im Code dupliziert. Sie können die Typentabelle in eine zwischengespeicherte Liste laden.

Class GenderList

   Public Shared Property UnfilteredList
   Public Shared Property Male = GetItem("M")
   Public Shared Property Female = GetItem("F")

End Class

Geben Sie oft kommen und gehen. Sie benötigen ein Datum, an dem der neue Typ hinzugefügt wurde. Wissen, wann ein bestimmter Typ entfernt wurde. Zeigen Sie es nur bei Bedarf an. Was ist, wenn ein Kunde "Transgender" als Geschlecht möchte, andere Kunden jedoch nicht? Alle diese Informationen werden am besten in der Datenbank gespeichert.

0
the_lotus