Beste Weg, um statische Datenbankdaten im Code zu referenzieren?

24

Viele Anwendungen enthalten "statische Daten": Daten, die sich während der Lebensdauer der Anwendung nicht wirklich ändern. Beispielsweise könnten Sie eine Liste von Verkaufsbereichen haben, die auf absehbare Zeit wahrscheinlich eine feste Liste ist.

Es ist nicht ungewöhnlich, diese statischen Daten in einer Datenbanktabelle zu finden (häufig, weil Sie in den Fremdschlüsseln anderer Tabellen darauf verweisen möchten). Eine einfache Beispieltabelle enthält eine ID als Primärschlüssel und eine Beschreibung. Beispielsweise enthält Ihre SalesArea-Tabelle (mindestens) eine SalesAreaId-Spalte und eine SalesAreaDescription-Spalte.

Im Code möchten Sie möglicherweise nicht jede Zeile der Tabelle gleich behandeln. Beispielsweise möchten Sie auf einigen Bildschirmen möglicherweise einen Standardverkaufsbereich festlegen, für einige Bereiche andere Zahlen angeben oder die Möglichkeiten der Benutzer in anderen Bereichen einschränken.

Wie kann man am besten auf diese statischen Daten im Code verweisen? Warum?

  1. Codieren Sie die Beschreibungen in Ihrem Code hart. Verwenden Sie diese Option, um die SalesAreaId bei Bedarf in der Datenbank nachzuschlagen.
  2. Kodieren Sie die IDs in Ihrem Code fest. Verwenden Sie diese Option, um die SalesAreaDescription bei Bedarf nachzuschlagen.
  3. Fügen Sie der Tabelle für jeden Zweck eine Spalte hinzu, z. B. eine "IsDefaultOnProductLaunchScreen" -Spalte usw. (es kann viele davon geben).
  4. Etwas anderes.

Gibt es weitere spezielle Überlegungen, die ich beim Umgang mit statischen Datenbankdaten treffen sollte? Zum Beispiel diesen Tabellen einen speziellen Namen geben?

Kramii setzt Monica wieder ein
quelle
1
Mögliches Duplikat: programmers.stackexchange.com/questions/304169/… Ich glaube, die Antworten auf diese Frage (verknüpft) bringen das Problem auf den Punkt, IMO
JoeCool

Antworten:

14

Wie wäre es, wenn Sie diese beim Start der Anwendung in einen Cache laden (normalerweise als Hash-Tabelle implementiert)? Wenn Sie das tun, müssen Sie nicht einmal die Datenbank abfragen (also nicht mehr als einmal).

Ich würde auch empfehlen, auf das Hardcodieren zu verzichten. Fügen Sie Standardkennzeichen (anfangs in der DB-Tabelle und auch in der Cache-Struktur) für Bildschirme hinzu, die Standardwerte benötigen. Versuchen Sie, die Schlüssel, die nachgeschlagen werden sollen, in einer Konfigurations- oder Eigenschaftendatei zu speichern, falls dies möglich ist.

FrustratedWithFormsDesigner
quelle
Zwischenspeichern ist natürlich gut, aber wie aktualisieren Sie diese Werte? Vermutlich ein Neustart der Anwendung oder eine Cache-Invalidierungsstrategie?
Steve
1
@Steve Ja genau. Kommt auf die Anwendung an. Neustart ist gut für etwas, das häufig beginnt. Bei einer Anwendung mit langer Laufzeit wird der Cache in langsamen Zeiten möglicherweise einmal täglich neu geladen. Meine Frage wäre, was ist mit einem Szenario, in dem die Anwendung viele sehr kurzlebige Zeiten ausgeführt wird. Zum Beispiel ein PHP-Skript oder ähnliches.
tylermac
Die Datenbank führt einen eigenen Cache für häufig aufgerufene Daten aus, sodass Sie etwas erneut implementieren, das bereits implementiert ist (und wahrscheinlich auch nicht!)
James Anderson
@JamesAnderson: Caching in der Anwendung bedeutet, dass die Datenbank immer nur einmal aufgerufen wird. Ja, Datenbanken haben ihre eigenen Caches, aber diese können durch Ereignisse außerhalb der Kontrolle Ihrer Anwendung ungültig gemacht / aktualisiert werden. Sie müssen weiterhin eine Verbindung zur Datenbank herstellen und eine Abfrage durchführen, um diese Daten abzurufen (und hoffen, dass sie in der Datenbank gespeichert sind db's cache). Es ist wirklich nicht so schwierig, einen einfachen anwendungsinternen Cache zu implementieren.
FrustratedWithFormsDesigner
7

Eine Alternative zur Datenbank oder zur Hardcodierung ist die Verwendung einer Konfigurationsdatei, die beim Start gelesen wird. Sie können diese Daten dann in einer schreibgeschützten Struktur in Ihrem Code speichern.

In dem seltenen (aber nicht unmöglichen) Fall, dass Sie diese Daten bearbeiten, müssen Sie die App neu starten. Wenn dies nicht möglich ist, können Sie einen komplexeren Konfigurationsmanager schreiben, der jedes Mal, wenn auf die Daten zugegriffen wird, nach Änderungen in der Konfigurationsdatei sucht. Dies ist sehr effizient, da Sie nur einen Zeitstempel für die Datei überprüfen und dann alle Daten ungültig machen müssen wenn die Datei aktualisiert wird.

Steve
quelle
1
Gute Idee für einige Arten statischer Daten, aber nicht so gut, wenn Sie FK-Beziehungen erzwingen möchten, wie in der Frage beschrieben.
Kramii setzt Monica
Frage sagte nicht, dass dies eine Anforderung war, nur ein Szenario. Wenn es nicht benötigt wird, funktioniert der Ansatz der Konfigurationsdatei gut.
Steve
Du hast recht, ich war nicht klar genug. Aber ich freue mich ... weil ich aus Ihrer Antwort etwas gelernt habe. Ich bin noch nie auf diesen Ansatz gestoßen.
Kramii setzt Monica
3

Wenn sich die Daten auf vorhandene Daten in Ihrer Datenbank beziehen, ist das Hinzufügen zur Datenbank wahrscheinlich genauso effizient wie das Hinzufügen zum Code. Wenn dies nicht der Fall ist, bin ich normalerweise versucht, "diese Kugel einmal zu nehmen" und sie bis zur ersten Änderung in den Code einzufügen.

Was wir für statisch halten, stellt sich oft als nicht statisch heraus. In diesem Fall müssen Sie nicht auf eine Code-Freigabe warten, bis eine Änderung durchgeführt wird. Sobald dies einmal passiert, legen Sie es in die Datenbank und schreiben Sie eine Administratorseite, um weitere Aktualisierungen vorzunehmen.

Wenn Sie beispielsweise bereits Verkaufsbereiche in der Datenbank haben, fügen Sie dort eine Beschreibung hinzu, und erstellen Sie keine Hash-Tabelle, um die Datenbankdaten mit fest codierten Listen in Beziehung zu setzen. Wenn Sie dann aber nicht unbedingt eine Hash-Tabelle mit Verkaufsbereichen erstellen, sondern bereit sind, verschieben Sie diese in die DB, wenn zum ersten Mal jemand eine Beschreibung ändert oder einen neuen Verkaufsbereich hinzufügt.

pdr
quelle
"Oft stellt sich heraus, dass das, was wir für statisch halten, nicht so ist" - so wahr.
Kramii setzt Monica
3

Warum nicht einfach alles hart codieren? Das Hauptproblem, das ich immer hatte, ist das Verweisen auf statische Werte aus der Datenbank im Anwendungscode. Es ist eine Sache, wenn Sie direkt eine Dropdown-Liste oder etwas aus statischen Werten erstellen, aber was ist, wenn eine Anwendungslogik von den Werten aus der Datenbank abhängt?

In einer einfachen App habe ich derzeit eine Liste mit Bearbeitungsstatus für Inhaltselemente: Entwurf, Veröffentlicht, Archiviert.

Die Inhaltselemente müssen je nach Status unterschiedlich behandelt werden. Wenn ich diese Statusdaten in der Datenbank mit den Werten 1, 2 bzw. 3 behalten würde, wie würde ich dann prüfen, ob sich etwas in Entwurf befindet Zustand?

if (content.State == 1)
oder
if (content.State == "Draft")?

Ich habe die Werte nur hart codiert!
Dasselbe gilt, wenn Sie eine Cache- / Hash-Tabelle verwenden: Sie müssen immer noch einen in Ihrem Code geschriebenen Wert als Schlüssel verwenden, um Ihre Daten nachzuschlagen.

Was sind die Nachteile des Hard-Coding-Ansatzes?

Dave
quelle
Der Nachteil ist, wie pdr sagte: "Oft stellt sich heraus, dass das, was wir für statisch halten, nicht so ist".
tylermac
2
Wenn Sie jedoch tatsächlich auf die statischen Datenwerte im Code verweisen, können Sie diese in der Datenbank nicht ändern, ohne die App zu beschädigen. Natürlich hängt es davon ab, wofür die Daten verwendet werden: Wie oben erwähnt, wird nur ein Benutzeroberflächenelement aufgefüllt, damit ein Benutzer einen Wert auswählen und diesen als Teil eines Datensatzes in einer anderen Tabelle direkt an die Datenbank weiterleiten kann können sich dann die statischen Daten in der DB unabhängig vom App-Code ändern. Ich bin mir ziemlich sicher, dass dies die Situation ist, über die @pdr spricht: die App, die den Satz statischer Daten als ein einzelnes Element behandelt.
Dave
2

Ähnlich wie bei FrustratedWithFormsDesigner wird dies normalerweise mit einem Cache durchgeführt, da Sie die statischen Daten immer nur einmal laden müssen, sie jedoch dem OAOO-Muster folgen, dh, wir definieren die Daten nicht an zwei Stellen (Datenbank und in dein Code).

Ich weiß, dass der NHibernate ORM diese Funktionalität über einen 2nd Level Cache bietet . Sie können festlegen, dass Daten aus einer bestimmten Tabelle zwischengespeichert werden sollen und dass sie schreibgeschützt sind. Es wird das erste Mal geladen, wenn es benötigt wird. Danach wird die Datenbank nicht erneut aufgerufen, selbst wenn Sie von mehreren Sitzungen aus auf die Daten zugreifen.

Scott Whitlock
quelle
+1 für einmal und nur einmal. Aber was ist mit der unterschiedlichen Behandlung von Zeilen?
Kramii setzt Monica
1
@ Kramii - Sie können so etwas wie Aufzählungsklassen verwenden . Wenn sich die Metadaten nur auf Ihr Programm beziehen, würde ich die Geschäftslogik ( IsDefaultOn...) in eine Eigenschaft der Entität einfügen. Lassen Sie es für die eine Entität wahr zurückgeben. Auf diese Weise können Sie diese Entität in Anbetracht der gesamten Sammlung finden. Sie können auch eine Controller-Klasse verwenden, die der entsprechenden Entität einen Methodenaufruf bereitstellt.
Scott Whitlock
2

Dies ist im schlimmsten Fall eine vorzeitige Optimierung.

Erstens ruft jedes moderne DBMS blitzschnell Daten von kleinen Tabellen ab und alle verfügen über Caching-Algorithmen von gut bis hervorragend (je mehr Sie für das DBMS bezahlt haben, desto besser ist das Cachen!). Sie optimieren also etwas, das nur minimale Ressourcen verbraucht.

Zweitens haben Sie nur sehr wenig Erfahrung mit realen Geschäftsanwendungen, wenn Sie sich vorstellen, dass ein "Verkaufsbereich" statische Daten sind. Diese können sich mit jedem Wechsel des Marketing Director oder CEO ändern. Sie befinden sich also zwei Jahre später auf dem Weg in eine Welt der Schmerzen.

Hier gibt es nur zwei Möglichkeiten:

Speichern Sie es in einer Datenbank und greifen Sie mit "normalem" SQL auf die Daten zu.

Speichern Sie es in einer schicken XML-Konfigurationsdatei (möglicherweise über REST oder SOAP zugänglich), die bei jeder "strategischen Änderung der Richtlinie" einfach bearbeitet werden kann.

James Anderson
quelle
1

Es hängt davon ab, was Sie mit den Daten machen. Wenn es eine Liste von etwas ist, ziehe ich es normalerweise in ein Array. Wenn die Liste in einer anderen Version erweitert werden muss, können Sie sie einfach zur Datenbank hinzufügen und den Code ändern, um die zusätzlichen Daten im Array zu verarbeiten (was je nach Code möglicherweise nicht erforderlich ist, z. B. Auflisten der Daten mit einem for-Schleife unter Verwendung der oberen Grenze des Arrays). Wenn es sich um eine Liste von Einstellungen handelt, werde ich diese normalerweise hart codieren, da es normalerweise nicht viele gibt und dies einfacher und schneller ist als die Verwendung einer SQL-Anweisung. Wenn der Benutzer diese Einstellung ändern kann und ich die Auswahl für nachfolgende Starts speichern möchte, erstelle ich eine Tabelle, die als Registrierung verwendet wird, und rufe nach Bedarf einzelne Einträge zu Variablen auf.

MaQleod
quelle
1

Ich weiß, dass diese Antwort akzeptiert wurde, aber ich wollte mitteilen, wie wir dies in meinem letzten Webentwicklungs-Shop getan haben, in dem wir versucht haben, die Datenbank-E / A so weit wie möglich zu reduzieren.

Wir haben serverseitige Include-Dateien für so viele Datenstrukturen wie möglich verwendet. Dies war hauptsächlich für die Seitennavigation gedacht (einschließlich Unternavigation), wir haben es jedoch auch für so viele Dropdowns und Kontrollkästchen wie möglich verwendet (Bundesstaaten, Länder, Kategorien).

Ursprünglich haben wir all diese Daten aus der Datenbank gezogen. Da wir dem Kunden ein Administrations-Widget zur Verfügung gestellt haben, konnten sie diese Daten nach Belieben ändern, und wir wurden nie mit kleinen kleinen Änderungen konfrontiert. Meistens änderten sich diese Daten kaum, aber gelegentlich änderten sie sich.

Wir haben immer nach schnelleren Ladezeiten gesucht. Deshalb haben wir beschlossen, so viele statische serverseitige Textdateien wie möglich zu implementieren. Wir haben dies neben dem Admin-Widget getan. Bei jeder Aktualisierung einer Datenbanktabelle wurde die entsprechende statische Textdatei neu generiert. Dies gab uns ein sehr flexibles und schnelles Umfeld.

Michael Riley - AKA Gunny
quelle
0

Meine Lösung hierfür, die möglicherweise nicht in allen Situationen funktioniert, besteht darin, die statischen Datenbankdaten an eine fest codierte zu binden enum. Da das Problem darin besteht, dass dynamische Daten (Datenbank) an statische Logik (Code) gebunden sind, machen Sie diese Bindung explizit (und locker), indem Sie eine Datenbanktabelle verwenden, die der zugeordnet ist enum. Ex:

LooseDBCodeBinding (database table)
   ID : Int32 (key)
   Name : String
   HardCodedTypeID : Int32

// in code:
public enum LooseDBCodeBinding
{
   TYPE_1 = 1,
   TYPE_2 = 2,
   TYPE_3 = 3 // etc...
}

Schreiben Sie dann eine Benutzeroberfläche, mit der Sie die Liste der LooseDBCodeBindingDatensätze auf einfache Weise anzeigen und LooseDBCodeBinding enumWerte zuordnen können (einschließlich der Unterstützung von "defekten" Bindungen). Sie können dann enumum den Tabellenschlüssel herum programmieren und die Datenbank entwerfen, und es ist nur diese eine Tabelle, die beide Kontexte kennt.

Dave Cousineau
quelle