Ich denke, dies ist eine weitere Frage zu Hardcodierung und Best Practices. Angenommen, ich habe eine Liste von Werten, beispielsweise Obst, die in der Datenbank gespeichert sind (sie muss in der Datenbank vorhanden sein, da die Tabelle für andere Zwecke wie SSRS-Berichte verwendet wird), mit einer ID:
1 Apple
2 Banana
3 Grapes
Ich kann sie dem Benutzer präsentieren, er wählt eine aus, sie wird in seinem Profil als FavouriteFruit gespeichert und die ID in seinem Datensatz in der Datenbank gespeichert.
Was sind die Empfehlungen für die Zuweisung von Logik zu bestimmten Werten, wenn es um Geschäftsregeln / Domänenlogik geht? Sagen Sie, wenn der Benutzer Trauben ausgewählt hat, die ich für eine zusätzliche Aufgabe ausführen möchte, wie lässt sich der Traubenwert am besten ermitteln:
// Hard coded name
if (user.FavouriteFruit.Name == "Grapes")
// Hard coded ID
if (user.FavoriteFruit.ID == 3) // Grapes
// Duplicate the list of fruits in an enum
if (user.FavouriteFruit.ID == (int)Fruits.Grapes)
oder etwas anderes?
Da FavouriteFruit natürlich in der gesamten Anwendung verwendet wird, kann die Liste hinzugefügt oder bearbeitet werden.
Jemand könnte entscheiden, dass "Trauben" in "Trauben" umbenannt werden soll, und dies würde natürlich die fest codierte Zeichenfolgenoption aufheben.
Die fest codierte ID ist jedoch nicht vollständig klar, wie gezeigt, können Sie einfach einen Kommentar hinzufügen, um schnell zu erkennen, um welchen Artikel es sich handelt.
Die Enum-Option beinhaltet das Duplizieren von Daten aus der Datenbank, was falsch zu sein scheint, da sie möglicherweise nicht mehr synchron sind.
Trotzdem vielen Dank im Voraus für Kommentare oder Vorschläge.
MyApplication.Grape.ID
stottert sozusagen. Ein "Apple" ist kein "Red_Apple" und nicht mehr als ID 3 ist auch 4. Das Potenzial, "Apple" in "Red_Apple" umzubenennen, ist also nicht sinnvoller, als zu deklarieren, dass 3 4 ist (und vielleicht sogar 3). Ziel einer Aufzählung ist es, ihre numerische DNA zu abstrahieren. Vielleicht ist es an der Zeit, beliebige relationale DB-Schlüssel, die in den eigenen Geschäftsmodellen buchstäblich keine Bedeutung haben , wirklich zu entkoppeln.Antworten:
Vermeiden Sie unbedingt Zeichenfolgen und magische Konstanten. Sie kommen überhaupt nicht in Frage, sie sollten nicht einmal als Optionen betrachtet werden. Dies scheint Ihnen nur eine praktikable Option zu lassen: Bezeichner, also Aufzählungen. Es gibt jedoch noch eine Option, die meiner Meinung nach die beste ist. Nennen wir diese Option "Vorinstallierte Objekte". Mit vorinstallierten Objekten können Sie Folgendes tun:
Was hier gerade passiert ist, ist, dass ich offensichtlich die gesamte Zeile von
Grape
in den Speicher geladen habe, so dass ich ihre ID bereit habe, um sie für Vergleiche zu verwenden. Wenn Sie zufällig Object-Relational Mapping (ORM) verwenden, sieht es noch besser aus:(Deshalb nenne ich es "vorinstallierte Objekte".)
Was ich also tue, ist, dass ich während des Startvorgangs alle meine "Aufzählungstabellen" (kleine Tabellen wie Wochentage, Monate des Jahres, Geschlechter usw.) in die Hauptklasse der Anwendungsdomäne lade. Ich lade sie namentlich, weil offensichtlich
MyApplication.Grape
die Zeile "Grape" erhalten muss, und ich behaupte, dass jeder von ihnen gefunden wird. Wenn nicht, haben wir einen garantierten Laufzeitfehler während des Startvorgangs, der von allen Laufzeitfehlern am wenigsten bösartig ist.quelle
Grape = fetchRow( Fruit.class, NameColumn, "Grape" );
Und wenn Sie Tun Sie etwas falsch,AssertionError
und Sie werden es wissen lassen.enum
eine magische Zeichenfolge gewesen wäre. Der Punkt ist die Konzentration aller Bindungen an nur einer Stelle , die Validierung aller Bindungen während des Startvorgangs und die Typensicherheit .Die Prüfung anhand der Zeichenfolge ist am besten lesbar, hat jedoch doppelte Funktion: Sie wird sowohl als Bezeichner als auch als Beschreibung verwendet (was sich aus nicht verwandten Gründen ändern kann).
Normalerweise teile ich beide Aufgaben in separate Felder auf:
Wo sich die Beschreibung ändern kann (aber nicht "Trauben" zu "Banane"), darf sich der Code niemals ändern.
Dies liegt zwar hauptsächlich daran, dass unsere IDs fast immer automatisch generiert werden und daher nicht gut passen. Wenn Sie IDs frei wählen können, können Sie möglicherweise garantieren, dass sie immer korrekt sind, und diese verwenden.
Wie oft bearbeitet jemand "Trauben" wirklich in "Trauben"? Vielleicht ist nichts davon notwendig.
quelle
Was Sie hier erwarten, ist, dass die Programmierlogik automatisch an sich ändernde Daten angepasst werden kann. Einfache statische Optionen wie Enum funktionieren hier nicht, weil Sie in der Laufzeit keine zusätzlichen Enums hinzufügen können.
Ein paar Muster, die ich gesehen habe:
Im Allgemeinen finde ich es gut, wenn Daten vollständig sind, wenn sie sich auf implizite Aktionen beziehen - auch wenn die Aktionen selbst an anderer Stelle implementiert werden könnten. Jeder Code, der Aktionen unabhängig von den Daten bestimmt, hat gerade Ihre Datendarstellung zerstört, was höchstwahrscheinlich zu Abweichungen und Fehlern führen wird.
quelle
Das Speichern an beiden Orten (in einer Tabelle und in einem ENUM) ist nicht so schlecht. Die Begründung lautet wie folgt:
Durch Speichern in einer Datenbanktabelle können wir die referenzielle Integrität in der Datenbank über Fremdschlüssel erzwingen. Wenn Sie also eine Person oder eine beliebige Entität einer Frucht zuordnen, ist dies nur eine Frucht, die in der Datenbanktabelle vorhanden ist.
Das Speichern als ENUM ist auch deshalb sinnvoll, weil wir Code ohne magische Zeichenfolgen schreiben können und der Code dadurch besser lesbar wird. Ja, sie müssen synchron bleiben, aber wie schwierig wäre es wirklich, der ENUM eine Zeile und der Datenbank eine neue insert-Anweisung hinzuzufügen.
Wenn eine ENUM definiert ist, darf der Wert nicht mehr geändert werden. Zum Beispiel, wenn Sie:
Benennen Sie Trauben NICHT in Trauben um. Fügen Sie einfach eine neue ENUM hinzu.
Wenn Sie Daten migrieren müssen, wenden Sie ein Update an, um alle Trauben in Trauben zu verschieben.
quelle
Sie haben Recht, diese Frage zu stellen. Eigentlich ist es eine schöne Frage, wenn Sie versuchen, sich gegen die Bewertung ungenauer Bedingungen zu verteidigen.
Das heißt, die Bewertung (Ihre
if
Bedingungen) muss nicht unbedingt im Mittelpunkt der Art und Weise stehen, wie Sie damit umgehen. Achten Sie stattdessen darauf, wie Sie die Änderungen verbreiten, die zu einem nicht synchronen Problem führen würden.String-Ansatz
Wenn Sie Zeichenfolgen verwenden müssen, können Sie die Funktionalität zum Ändern der Liste über die Benutzeroberfläche bereitstellen. Konzipieren Sie das System so , dass bei einem Wechsel
Grape
aufGrapes
, zum Beispiel, aktualisieren Sie alle Datensätze zur Zeit verweisenGrape
.ID-Ansatz
Ich würde es immer vorziehen, auf eine ID zu verweisen, obwohl die Lesbarkeit eingeschränkt ist.
The list may be added to
kann wieder etwas sein, über das Sie benachrichtigt werden, wenn Sie eine solche UI-Funktion verfügbar machen. Wenn Sie sich mit der Neuordnung von Elementen befassen, die die ID ändern, geben Sie diese Änderung erneut an alle abhängigen Datensätze weiter. Ähnlich wie oben. Eine andere Option (gemäß der Normierungskonvention wäre, eine Spalte mit Ihrer Enumeration / ID zu haben - und auf eine detailliertereFruitDetail
Tabelle zu verweisen , die eine Spalte mit der Bezeichnung "Reihenfolge" enthält, die Sie nachschlagen können).Wie auch immer, Sie sehen, ich schlage vor, die Änderung oder Aktualisierung Ihrer Liste zu kontrollieren. Ob Sie dies mithilfe eines ORM oder eines anderen Datenzugriffs tun, hängt von den Besonderheiten Ihrer Technologie ab. Was Sie im Wesentlichen tun, ist, dass Leute, die sich von der DB entfernen, solche Änderungen vornehmen müssen - was meiner Meinung nach in Ordnung ist. Die meisten Haupt-CRMs stellen die gleichen Anforderungen.
quelle
Ein sehr häufiges Problem. Das Duplizieren der Daten-Client-Seite scheint zwar gegen die DRY- Prinzipien zu verstoßen , ist jedoch auf den Paradigmenunterschied zwischen den Ebenen zurückzuführen.
Es ist auch nicht ungewöhnlich, dass die Aufzählung (oder was auch immer) nicht mit der Datenbank Schritt hält. Möglicherweise haben Sie einen anderen Wert in eine Metadatentabelle verschoben, um eine neue Berichtsfunktion zu unterstützen, die im clientseitigen Code noch nicht verwendet wird.
Manchmal passiert es auch anders herum. Ein neuer Aufzählungswert wird auf der Clientseite hinzugefügt, aber das DB-Update kann erst durchgeführt werden, wenn der DBA die Änderungen übernehmen kann.
quelle
Unter der Annahme, dass es sich im Wesentlichen um eine statische Suche handelt, ist die dritte Option - die Aufzählung - im Wesentlichen die einzig vernünftige Wahl. Es ist das, was Sie tun würden, wenn die Datenbank nicht involviert wäre, also macht es Sinn.
Die Frage ist dann die, wie man Enums und statische / Nachschlagetabellen in der Datenbank synchron hält, und leider ist das kein Problem, auf das ich noch eine vollständige Antwort habe.
Wahlweise führe ich alle Schemawartungen im Code durch und kann daher eine Beziehung zwischen einem Build der Anwendung und einer erwarteten Schemaversion aufrechterhalten, sodass es einfach ist, die Suche und die Aufzählung synchron zu halten, aber es ist etwas, an das man sich erinnern muss machen. Es wäre besser, wenn es automatisierter wäre (und auch ein automatisierter Integrationstest, um sicherzustellen, dass die Aufzählungen und Nachschlageergebnisse übereinstimmen), aber das habe ich noch nie implementiert.
quelle