Entwürfe und Vorgehensweisen zum Schutz vor fehlerhaften Null-Einträgen aus der Datenbank

9

Ein Teil meines Programms ruft Daten aus vielen Tabellen und Spalten in meiner Datenbank zur Verarbeitung ab. Einige der Spalten sind möglicherweise vorhanden null, aber im aktuellen Verarbeitungskontext ist dies ein Fehler.

Dies sollte "theoretisch" nicht passieren. Wenn dies der Fall ist, deutet dies auf fehlerhafte Daten oder einen Fehler im Code hin. Die Fehler haben je nach Feld unterschiedliche Schweregrade null. dh für einige Felder sollte die Verarbeitung gestoppt und jemand benachrichtigt werden, für andere sollte die Verarbeitung fortgesetzt werden dürfen und nur jemand benachrichtigt werden.

Gibt es gute Architektur- oder Designprinzipien, um mit den seltenen, aber möglichen nullEinträgen umzugehen?

Die Lösungen sollten mit Java implementiert werden können, aber ich habe das Tag nicht verwendet, da ich denke, dass das Problem etwas sprachunabhängig ist.


Einige Gedanken, die ich selbst hatte:

Verwenden von NOT NULL

Am einfachsten wäre es, eine NOT NULL-Einschränkung in der Datenbank zu verwenden.

Was aber, wenn das ursprüngliche Einfügen der Daten wichtiger ist als dieser spätere Verarbeitungsschritt? Für den Fall, dass die Einfügung ein nullin die Tabelle einfügt (entweder aufgrund von Fehlern oder vielleicht sogar aus einem gültigen Grund), möchte ich nicht, dass die Einfügung fehlschlägt. Nehmen wir an, dass viele weitere Teile des Programms von den eingefügten Daten abhängen, jedoch nicht von dieser bestimmten Spalte. Daher würde ich lieber den Fehler im aktuellen Verarbeitungsschritt als im Einfügeschritt riskieren. Deshalb möchte ich keine NOT NULL-Einschränkung verwenden.

Naiv abhängig von NullPointerException

Ich könnte die Daten einfach so verwenden, als ob ich erwarte, dass sie immer vorhanden sind (und das sollte wirklich der Fall sein), und die resultierenden NPEs auf einer angemessenen Ebene abfangen (z. B. damit die Verarbeitung des aktuellen Eintrags stoppt, aber nicht der gesamte Verarbeitungsfortschritt ). Dies ist das Prinzip "schnell scheitern" und ich bevorzuge es oft. Wenn es zumindest ein Fehler ist, bekomme ich eine protokollierte NPE.

Aber dann verliere ich die Fähigkeit, zwischen verschiedenen Arten fehlender Daten zu unterscheiden. Zum Beispiel könnte ich einige fehlende Daten weglassen, aber für andere sollte die Verarbeitung gestoppt und ein Administrator benachrichtigt werden.

Überprüfen auf nullvor jedem Zugriff und werfen benutzerdefinierte Ausnahmen

Mit benutzerdefinierten Ausnahmen kann ich anhand der Ausnahme die richtige Aktion festlegen. Dies scheint also der richtige Weg zu sein.

Aber was ist, wenn ich vergesse, es irgendwo zu überprüfen? Außerdem überfülle ich meinen Code dann mit Nullprüfungen, die nie oder selten erwartet werden (und daher definitiv nicht Teil des Geschäftslogikflusses sind).

Wenn ich mich für diesen Weg entscheide, welche Muster eignen sich am besten für den Ansatz?


Alle Gedanken und Kommentare zu meinen Ansätzen sind willkommen. Auch bessere Lösungen jeglicher Art (Muster, Prinzipien, bessere Architektur meines Codes oder meiner Modelle usw.).

Bearbeiten:

Es gibt eine weitere Einschränkung, da ich ein ORM verwende, um die Zuordnung von DB zu Persistenzobjekt durchzuführen, sodass Nullprüfungen auf dieser Ebene nicht funktionieren würden (da dieselben Objekte in Teilen verwendet werden, in denen die Null keinen Schaden anrichtet). . Ich habe dies hinzugefügt, weil in den bisher gegebenen Antworten beide diese Option erwähnt haben.

Jhyot
quelle
5
"Einige der Spalten sind möglicherweise null, aber im aktuellen Verarbeitungskontext ist dies ein Fehler. ... falls die Einfügung eine Null in die Tabelle einfügen würde, möchte ich nicht, dass die Einfügung fehlschlägt." Diese beiden Anforderungen sind widersprüchlich. Es ist unmöglich , eine Lösung zu finden, bis Sie eine der beiden Bedingungen entspannen.
Kilian Foth
@ KilianFoth Nun, meine Entspannung ist, dass der Fehler im Kontext "Aktuelle Verarbeitung" weniger schwerwiegend ist als beim Einfügen. Daher akzeptiere ich seltene Verarbeitungsfehler, möchte aber ein gutes, robustes Design haben, um sie zu behandeln. Deshalb ist NOT NULL, was sonst eine gute Lösung wäre, hier nicht möglich.
Jhyot
1
Wenn Sie so viele Fehler akzeptieren, werden die Urheber dieser Fehler diese niemals korrigieren. Welchen Anreiz haben sie jemals, Dinge zu reparieren, wenn ihre chaotischen Insert-Anweisungen erfolgreich sind? Halten Sie es für robust, nicht zu versagen, sondern schlechte Daten zu akzeptieren?
Tulains Córdova
@ user61852 Ich akzeptiere die Fehler ausdrücklich nicht, möchte sie aber ordnungsgemäß behandeln. Das Verschlucken von Nullzeigern kommt nicht in Frage. Was ist auch, wenn mein Teil wirklich objektiv (wie vom Unternehmen definiert) weniger wichtig ist als viele andere Teile, für die das Einfügen erfolgreich sein muss, für die jedoch kein bestimmtes Feld festgelegt werden muss? Die Einfügungen stammen nicht von einem Benutzereintrag, bei dem ich sie zwingen könnte, den Wert hinzuzufügen, sondern von anderem Code, bei dem das Auslassen höchstwahrscheinlich ein Fehler ist (aber nicht wichtig genug, um die Einfügung zu beschädigen).
Jhyot
1
Wenn Sie sie in der Datenbank als NICHT NULL markieren, ist dies die beste Lösung. Wenn eine Spalte nullwertfähig ist, muss der Code den Fall behandeln, auch wenn dies nicht erwartet wird, da der Speichermechanismus dies zulässt.
Jon Raynor

Antworten:

9

Ich würde die Nullprüfungen in Ihren Mapping-Code einfügen, in dem Sie Ihr Objekt aus der Ergebnismenge erstellen. Dadurch wird die Überprüfung an einem Ort durchgeführt, und Ihr Code kann nicht die Hälfte der Verarbeitung eines Datensatzes durchlaufen, bevor ein Fehler auftritt. Abhängig von der Funktionsweise Ihres Anwendungsflusses möchten Sie möglicherweise die Zuordnung aller Ergebnisse als Vorverarbeitungsschritt durchführen, anstatt jeden Datensatz einzeln zuzuordnen und zu verarbeiten.

Wenn Sie ein ORM verwenden, müssen Sie alle Ihre Nullprüfungen durchführen, bevor Sie jeden Datensatz verarbeiten. Ich würde eine recordIsValid(recordData)Methode vom Typ "Typ" empfehlen . Auf diese Weise können Sie (erneut) die gesamte Nullprüfungs- und andere Validierungslogik an einem Ort aufbewahren. Ich würde die Nullprüfungen definitiv nicht mit dem Rest Ihrer Verarbeitungslogik vermischen.

TMN
quelle
Danke, das ist ein guter Einblick! Ich verwende in der Tat ein ORM, daher funktionieren Überprüfungen auf dieser Ebene nicht. Ich habe aber auch einige Zuordnungen zu realen Domänenobjekten aus den Persistenzobjekten. Ich werde prüfen, ob die Zuordnung und Validierung in einem Vorverarbeitungsschritt möglich ist.
Jhyot
Und wenn Sie Ihren ORM wechseln, was dann? Besser, dies an der Quelle zu verteidigen (siehe Doc Browns Antwort).
Robbie Dee
@RobbieDee: Sollte keine Rolle spielen. Wenn Sie den Zuordnungscode neu schreiben müssen, sind entweder die Nullprüfungen vorhanden und Sie ändern sie als Teil des Umschreibens, oder Sie haben eine separate Methode, die die Nullprüfungen für Ihre Geschäftsobjekte durchführt, sodass kein Umschreiben erforderlich ist. Und wie Doc Brown andeutet, ist es manchmal wichtig zu bemerken, dass Daten fehlen, anstatt diese Tatsache mit einem Standardwert zu beschönigen.
TMN
Dies sollte weiter oben im ETL-Fluss geschehen. Auf diese Weise riskieren Sie immer noch Doppelarbeit.
Robbie Dee
6

Es klingt so, als wäre das Einfügen einer Null ein Fehler, aber Sie haben Angst, diesen Fehler beim Einfügen zu erzwingen, weil Sie keine Daten verlieren möchten. Wenn ein Feld jedoch nicht null sein sollte, sondern verloren geht, gehen Daten verloren . Daher besteht die beste Lösung darin, sicherzustellen, dass Nullfelder nicht fälschlicherweise gespeichert werden.

Erzwingen Sie zu diesem Zweck, dass die Daten in dem einen autorisierenden, permanenten Repository für diese Daten, der Datenbank, korrekt sind. Fügen Sie dazu nicht null Einschränkungen hinzu. Dann schlägt Ihr Code möglicherweise fehl, aber diese Fehler benachrichtigen Sie sofort über Fehler, sodass Sie Probleme beheben können, die bereits zu Datenverlust führen. Jetzt, da Sie Fehler leicht identifizieren können, testen Sie Ihren Code und testen Sie ihn zweimal. Sie können Fehler beheben, die zu Datenverlust führen, und dabei die nachgelagerte Verarbeitung der Daten erheblich vereinfachen, da Sie sich keine Gedanken über Nullen machen müssen.

Stellen Sie Monica wieder her
quelle
2
Danke für die Antwort. Ich bin damit einverstanden, dass Ihre Lösung der richtige Weg ist, und Sie haben es kurz formuliert. Einschränkungen außerhalb meines Einflussbereichs können es schwierig oder unmöglich machen (z. B. nicht verfügbare Ressourcen zum Testen oder zum automatischen Testen vorhandenen Codes), aber ich sollte auf jeden Fall überprüfen, ob diese Lösung funktioniert, bevor ich andere Methoden ausprobiere. In meinem ursprünglichen Denken habe ich vielleicht zu schnell angenommen, dass ich das Problem an der Quelle nicht beheben kann.
Jhyot
@jhyot Okay. Es ist frustrierend, wenn man Dinge nicht sauber machen kann. Hoffentlich ist meine Antwort zumindest für andere nützlich, die ähnliche Probleme haben, aber in der Lage sind, die Grundursache anzugreifen, anstatt das Chaos nachträglich zu beseitigen.
Stellen Sie Monica am
5

In Bezug auf diesen Satz in der Frage:

Dies sollte "theoretisch" nicht passieren. Wenn dies der Fall ist, deutet dies auf fehlerhafte Daten oder einen Fehler im Code hin.

Ich habe dieses Zitat immer geschätzt (mit freundlicher Genehmigung dieses Artikels ):

Ich finde es amüsant, wenn unerfahrene Programmierer glauben, dass ihre Hauptaufgabe darin besteht, das Abstürzen von Programmen zu verhindern. Ich kann mir vorstellen, dass dieses spektakuläre Fehlerargument für einen solchen Programmierer nicht so attraktiv wäre. Erfahrene Programmierer erkennen, dass korrekter Code großartig ist. Code, der abstürzt, könnte verbessert werden, aber falscher Code, der nicht abstürzt, ist ein schrecklicher Albtraum.

Grundsätzlich gilt: Es klingt so, als würden Sie das Postelsche Gesetz befürworten : "Seien Sie konservativ in dem, was Sie senden, seien Sie liberal in dem, was Sie akzeptieren." Obwohl dieses "Robustheitsprinzip" theoretisch großartig ist, führt es in der Praxis zu Software, die zumindest langfristig - und manchmal auch kurzfristig - nicht robust ist. (Vergleiche Eric Allmans Artikel The Robustness Principle Reconsidered , der eine sehr gründliche Behandlung des Themas darstellt, obwohl er sich hauptsächlich auf Anwendungsfälle von Netzwerkprotokollen konzentriert.)

Wenn Sie Programme, die nicht ordnungsgemäß Daten in die Datenbank eingefügt werden, werden diese Programme gebrochen und Notwendigkeit werden fixiert . Durch das Papier über das Problem wird es nur noch schlimmer. Dies ist das Software-Engineering-Äquivalent dazu, dass ein Süchtiger seine Sucht fortsetzen kann.

Pragmatisch gesehen müssen Sie jedoch manchmal zulassen, dass "gebrochenes" Verhalten zumindest vorübergehend fortgesetzt wird, insbesondere im Rahmen eines nahtlosen Übergangs von einem lockeren, gebrochenen Zustand in einen strengen, korrekten Zustand. In diesem Fall möchten Sie einen Weg finden, um das erfolgreiche Einfügen der falschen Einfügungen zu ermöglichen, aber dennoch zulassen, dass sich der "kanonische" Datenspeicher immer in einem korrekten Zustand befindet . Es gibt verschiedene Möglichkeiten, dies zu tun:

  • Verwenden Sie einen Datenbank-Trigger, um fehlerhafte Einfügungen in korrekte Einfügungen zu konvertieren, z. B. indem fehlende / Null-Werte durch Standardwerte ersetzt werden
  • Lassen Sie die falschen Programme in eine separate Datenbanktabelle einfügen, die "falsch" sein darf, und lassen Sie einen separaten geplanten Prozess oder einen anderen Mechanismus verwenden, der korrigierte Daten aus dieser Tabelle in den kanonischen Datenspeicher verschiebt
  • Verwenden Sie die abfrageseitige Filterung (z. B. eine Ansicht), um sicherzustellen, dass die aus der Datenbank abgerufenen Daten immer in einem korrekten Zustand sind, auch wenn sich die Daten in Ruhe nicht befinden

Eine Möglichkeit, all diese Probleme zu umgehen, besteht darin , eine API-Ebene einzufügen, die Sie zwischen Programmen, die Schreibvorgänge ausführen, und der tatsächlichen Datenbank steuern .

Es klingt so, als ob ein Teil Ihres Problems darin besteht, dass Sie nicht einmal alle Stellen kennen, an denen falsche Schreibvorgänge generiert werden - oder dass es einfach zu viele davon gibt, als dass Sie sie aktualisieren könnten. Das ist ein beängstigender Zustand, aber er hätte niemals entstehen dürfen.

Sobald Sie mehr als eine Handvoll Systeme erhalten, die Daten in einem kanonischen Produktionsdatenspeicher ändern dürfen, werden Sie in Schwierigkeiten geraten: Es gibt keine Möglichkeit, etwas an dieser Datenbank zentral zu verwalten . Besser wäre es, so wenig Prozessen wie möglich Schreibvorgänge zu erlauben und diese als "Gatekeeper" zu verwenden, die die Daten vorverarbeiten können, bevor sie nach Bedarf eingefügt werden. Der genaue Mechanismus hierfür hängt wirklich von Ihrer spezifischen Architektur ab.

Daniel Pryden
quelle
"Wenn Sie Programme haben, die Daten falsch in Ihre Datenbank einfügen, sind diese Programme defekt und müssen repariert werden." Das ist auch theoretisch großartig, aber in Wirklichkeit werden sie immer noch Aufzeichnungen hinzufügen, während einige Komitees weiterhin darüber debattieren, ob "NA" oder "Keine" verwendet werden soll.
JeffO
@JeffO: sollte kein Ausschuß , ob zu debattieren store „NA“, „None“, NULL, oder etwas anderes in der Datenbank. Nichttechnische Stakeholder sind daran beteiligt, welche Daten aus der Datenbank stammen und wie sie verwendet werden, nicht jedoch an der internen Darstellung.
Daniel Pryden
@DanielPryden: Bei meinem letzten Job hatten wir ein Architecture Review Board (mit einem DBA-Unterausschuss), das domänenübergreifende technische Änderungen überprüfte. Sehr technisch, aber sie trafen sich nur alle zwei Wochen und wenn Sie ihnen nicht genügend Details zur Verfügung stellten, würden sie eine Entscheidung aufschieben, bis Sie ... bei einem nachfolgenden Treffen. Die meisten nicht trivialen Systemänderungen, die nicht darin bestanden, Funktionen durch neuen Code hinzuzufügen, würden routinemäßig etwa einen Monat dauern.
TMN
@DanielPryden - Ich habe in Besprechungen mit dem oberen Management über Textfeldbezeichnungen diskutiert. Sie könnten argumentieren, dass dies nichts mit dem zu tun hat, was Sie in der Anwendung oder der Datenbank benennen werden, aber es tut es.
JeffO
Als Antwort auf Kommentare zum Erhalt zusätzlicher Genehmigungen für Änderungen dieser Art: Mein Punkt, dass die Werte "falsch" sind, setzt voraus, dass die zulässigen Werte bereits irgendwo dokumentiert sind - deshalb sagt das OP, dass diese Werte als Fehler betrachtet werden sollten. Wenn das Schema der Datenbank angegeben wird, um einen Wert zuzulassen, ist dieser Wert kein Fehler. Der Punkt ist, dass, wenn Sie Daten haben, die nicht mit Ihrem Schema übereinstimmen, etwas kaputt geht: Ihre Priorität sollte darin bestehen, dass die Daten und das Schema übereinstimmen. Je nach Team müssen möglicherweise die Daten, das Schema oder beides geändert werden.
Daniel Pryden
2

" Gibt es gute Architektur- oder Designprinzipien, um mit den seltenen, aber möglichen Null-Einträgen umzugehen? "

Einfache Antwort - ja.

ETL

Führen Sie eine Vorabverarbeitung durch, um sicherzustellen, dass die Daten von ausreichender Qualität sind, um in die Datenbank aufgenommen zu werden. Alles in der Drop-Datei sollte zurückgemeldet werden und alle sauberen Daten können in die Datenbank geladen werden.

Als jemand, der sowohl Wilderer (Entwickler) als auch Game Keeper (DBA) war, weiß ich aus bitterer Erfahrung, dass Dritte ihre Datenprobleme nur dann lösen können, wenn sie dazu gezwungen werden. Sich ständig nach hinten zu beugen und Daten zu massieren, ist ein gefährlicher Präzedenzfall.

Mart / Repository

In diesem Szenario werden Rohdaten in die Repository-Datenbank übertragen, und anschließend wird eine bereinigte Version in die Mart-Datenbank übertragen, auf die Anwendungen dann Zugriff haben.

Standardwerte

Wenn Sie sinnvolle Standardwerte auf Spalten anwenden können, sollten Sie dies tun, obwohl dies einige Arbeit erfordern kann, wenn es sich um eine vorhandene Datenbank handelt.

Früh scheitern

Es ist verlockend, Datenprobleme einfach am Gateway zur Anwendung, Berichtssuite, Benutzeroberfläche usw. zu beheben. Ich rate Ihnen dringend, sich nicht nur darauf zu verlassen. Wenn Sie ein anderes Widget in die Datenbank einbinden, treten möglicherweise wieder dieselben Probleme auf. Beheben Sie die Probleme mit der Datenqualität.

Robbie Dee
quelle
+1 Dies ist, was ich tun würde, um alle Daten zu sammeln und einen gültigen Datensatz für Ihre Bewerbung zu erstellen.
Kwebble
1

Wann immer Ihr Anwendungsfall es erlaubt, NULL sicher durch einen guten Standardwert zu ersetzen, können Sie die Konvertierung in den SELECTSQL-Anweisungen mit ISNULLoder durchführen COALESCE. Also statt

 SELECT MyColumn FROM MyTable

man kann schreiben

 SELECT ISNULL(MyColumn,DefaultValueForMyColumn) FROM MyTable

Dies funktioniert natürlich nur, wenn das ORM es erlaubt, die select-Anweisungen direkt zu bearbeiten oder veränderbare Vorlagen für die Generierung bereitzustellen. Man sollte sicherstellen, dass keine "echten" Fehler auf diese Weise maskiert werden. Wenden Sie sie daher nur an, wenn das Ersetzen durch einen Standardwert genau das ist, was Sie im Fall von NULL wollen.

Wenn Sie die Datenbank und das Schema ändern können und Ihr Datenbanksystem dies unterstützt, können Sie den spezifischen Spalten eine Standardwertklausel hinzufügen, wie von @RobbieDee vorgeschlagen. Dies erfordert jedoch auch das Ändern der vorhandenen Daten in der Datenbank, um zuvor eingefügte NULL-Werte zu entfernen, und die Möglichkeit, anschließend zwischen korrekten und unvollständigen Importdaten zu unterscheiden.

Aus eigener Erfahrung weiß ich, dass die Verwendung von ISNULL überraschend gut funktionieren kann. In der Vergangenheit musste ich eine Legacy-Anwendung warten, bei der die ursprünglichen Entwickler vergessen hatten, vielen Spalten NOT NULL-Einschränkungen hinzuzufügen, und wir konnten diese Einschränkungen später nicht einfach hinzufügen aus irgendwelchen Gründen. In 99% aller Fälle war 0 als Standard für Zahlenspalten und die leere Zeichenfolge als Standard für Textspalten völlig akzeptabel.

Doc Brown
quelle
Während dies funktioniert, müssen Sie möglicherweise den Verteidigungscode für jedes SELECT duplizieren. Ein weitaus besserer Ansatz besteht darin, einen Standardwert für eine Spalte zu definieren, wenn ein NULL-Wert eingefügt wird, obwohl dies aus verschiedenen Gründen möglicherweise nicht möglich / wünschenswert ist.
Robbie Dee
@RobbieDee: Danke für diese Bemerkung, ich habe meine Antwort entsprechend geändert. Ob dies jedoch "weitaus besser" ist, ist umstritten. Wenn sich der CRUD-Code an einer Stelle befindet, ist der doppelte Verteidigungscode möglicherweise kein großes Problem. Wenn dies nicht der Fall ist, gibt es bereits zuvor einige Codeduplikationen.
Doc Brown
Einfache CRUD-Operationen sind natürlich das Ideal. In der realen Welt verfügen Systeme jedoch häufig über komplexe Benutzeroberflächenansichten, benutzergenerierte Datenassistenten, Berichte usw. usw. Wie Sie bereits betont haben, müssen Standardwerte von Grund auf vorhanden sein oder zumindest einen anfänglichen Konvertierungsaufwand erfordern. Was Sie beschrieben haben, könnte in einer Industriebrachenentwicklung vorzuziehen sein.
Robbie Dee
Beste Antwort. Neue Anwendungen fügen normalerweise einige neue Daten hinzu, die möglicherweise außerhalb Ihrer Kontrolle liegen. Fehlerhafte NULL-Werte entstehen normalerweise beim Importieren von Altdaten in neu gestaltete Datenbanken. Hierfür sind die Einschränkungen deaktiviert, damit sie in wenigen Stunden statt in mehreren Tagen abgeschlossen werden können. "The Big Fail" tritt häufig auf, wenn die Datenbankadministratoren versuchen, die Einschränkungen wieder zu aktivieren. Da dies nie geplant war, scheut das Management häufig die Arbeitswochen, die häufig erforderlich sind, um die fehlerhaften Daten zu beheben. Alle Apps sollten NULL-Werte ordnungsgemäß verarbeiten, indem sie Standardeinstellungen einfügen und die fehlenden Daten melden oder anderweitig dazu auffordern.
DocSalvager
1

Das OP geht von einer Antwort aus, die Geschäftsregeln mit datenbanktechnischen Details verbindet.

Dies sollte "theoretisch" nicht passieren. Wenn dies der Fall ist, deutet dies auf fehlerhafte Daten oder einen Fehler im Code hin. Die Fehler haben unterschiedliche Schweregrade, je nachdem, welches Feld null ist. dh für einige Felder sollte die Verarbeitung gestoppt und jemand benachrichtigt werden, für andere sollte die Verarbeitung fortgesetzt werden dürfen und nur jemand benachrichtigt werden.

Dies sind alles Geschäftsregeln. Die Geschäftsregeln kümmern sich nicht um Null an sich. Nach allem, was es weiß, könnte die Datenbank null haben, 9999, "BOO!" ... Es ist nur ein weiterer Wert. Dass in einem RDBMS null interessante Eigenschaften und einzigartige Verwendungen aufweist, ist umstritten.

Das einzige, was zählt, ist, was "Nullheit" für die gegebenen Geschäftsobjekte bedeutet ...

Gibt es gute Architektur- oder Designprinzipien, um mit den seltenen, aber möglichen Null-Einträgen umzugehen?

Ja.

  • Stellen Sie Geschäftsregeln in Klassen.
  • Die Transliteration sollte sich in einer geeigneten Codeschicht befinden, die die Geschäftsklassen und den Datenspeicher entkoppelt. Wenn Sie es nicht in den ORM-Code einfügen können, fügen Sie es zumindest nicht in die Datenbank ein.
  • Machen Sie die Datenbank so dumm wie möglich, keine Geschäftsregeln hier. Selbst harmlose Dinge wie das Festlegen eines Werts werden Sie beißen . War dort.
  • Überprüfen Sie die Daten, die in die Datenbank gelangen und von dieser stammen. Und dies geschieht natürlich im Kontext der Geschäftsobjekte.

Das Auslösen einer Ausnahme beim Abrufen von Daten ist nicht sinnvoll.

Die Frage ist "soll ich 'schlechte' Daten speichern"? Es hängt davon ab, ob:

  • Möglicherweise werden fehlerhafte Daten verwendet. Speichern Sie niemals ungültige Objekte oder Objektzusammensetzungen. Komplexe Daten- / Geschäftsbeziehungen überall. Benutzer können zu jedem Zeitpunkt eine beliebige Funktion ausführen und möglicherweise diese Geschäftseinheit in einer Reihe von Kontexten verwenden. Die Auswirkung (falls vorhanden) fehlerhafter Daten zum Zeitpunkt der Speicherung ist nicht bekannt, da sie in hohem Maße von der zukünftigen Verwendung abhängen. Es gibt keinen einheitlichen Prozess für diese Daten.
  • Kann nicht fortfahren, wenn fehlerhafte Daten vorhanden sind - Speichern fehlerhafter Daten zulassen. Der nächste Schritt in einem Prozess kann jedoch erst fortgesetzt werden, wenn alles gültig ist. Zum Beispiel die Einkommenssteuer. Beim Abrufen aus der Datenbank weist die Software auf die Fehler hin und kann ohne Gültigkeitsprüfung nicht an das IRS gesendet werden.
Radarbob
quelle
0

Es gibt viele Möglichkeiten, mit Nullen umzugehen, daher wechseln wir von der Datenbankebene zur Anwendungsschicht.


Datenbankebene

Sie können Nullen verbieten ; obwohl es hier unpraktisch ist.

Sie können einen Standard pro Spalte konfigurieren :

  • es erfordert , dass die Säule sein abwesend vom insert, so dass nicht explizit null Einsetzen abdeckt
  • Es verhindert die Erkennung von Zeilen, in denen insertdiese Spalte fälschlicherweise übersehen wurde

Sie können einen Trigger so konfigurieren , dass beim Einfügen die fehlenden Werte automatisch berechnet werden:

  • Es ist erforderlich, dass die zur Durchführung dieser Berechnung erforderlichen Informationen vorhanden sind
  • es wird die verlangsamen insert

Abfrageebene

Sie können Zeilen überspringen, in denen eine Unannehmlichkeit nullvorliegt:

  • es vereinfacht die Hauptlogik
  • Es verhindert, dass die "fehlerhaften Zeilen" erkannt werden, sodass ein anderer Prozess erforderlich wäre, um sie zu überprüfen
  • Es erfordert, dass jede Abfrage instrumentiert wird

Sie können einen Standardwert in der Abfrage angeben:

  • es vereinfacht die Hauptlogik
  • Es verhindert, dass die "fehlerhaften Zeilen" erkannt werden, sodass ein anderer Prozess erforderlich wäre, um sie zu überprüfen
  • Es erfordert, dass jede Abfrage instrumentiert wird

Hinweis: Das Instrumentieren jeder Abfrage ist nicht unbedingt ein Problem, wenn Sie über eine automatisierte Methode zum Generieren verfügen.


Anwendungsschicht

Sie können die Tabelle vorab auf Verboten prüfennull :

  • es vereinfacht die Hauptlogik
  • Dies verbessert die Ausfallzeit
  • Es erfordert, dass die Vorabprüfung und die Anwendungslogik konsistent bleiben

Sie können die Verarbeitung unterbrechen, wenn Sie auf ein Verbotenes stoßen null:

  • Es wird vermieden, das Wissen darüber zu duplizieren, welche Spalten vorhanden sein können nullund welche nicht
  • es ist immer noch relativ einfach (nur ein Scheck + Rückkehr / Wurf)
  • Es erfordert, dass Ihr Prozess wieder aufgenommen werden kann (wenn Sie bereits eine E-Mail gesendet haben, möchten Sie diese nicht zweimal oder hundertmal senden!)

Sie können die Zeile überspringen, wenn Sie auf ein Verbotenes stoßen null:

  • Es wird vermieden, das Wissen darüber zu duplizieren, welche Spalten vorhanden sein können nullund welche nicht
  • es ist immer noch relativ einfach (nur ein Scheck + Rückkehr / Wurf)
  • Es ist nicht erforderlich, dass Ihr Prozess fortgesetzt werden kann

Sie können eine Benachrichtigung senden, wenn Sie auf eine verbotene Benachrichtigung stoßen null, entweder einzeln oder stapelweise. Dies ist eine Ergänzung zu den anderen oben beschriebenen Methoden. Am wichtigsten ist jedoch "Was dann?". Insbesondere wenn Sie erwarten, dass die Zeile gepatcht wird und erneut verarbeitet werden muss, müssen Sie möglicherweise sicherstellen, dass Sie bereits verarbeitete Zeilen von Zeilen unterscheiden können, die benötigt werden erneut verarbeitet werden.


In Anbetracht Ihrer Situation würde ich die Situation bei der Bewerbung behandeln und entweder kombinieren:

  • unterbrechen und benachrichtigen
  • überspringen und benachrichtigen

Ich würde dazu neigen , wenn möglich nur zu überspringen , um irgendwie einen gewissen Fortschritt zu garantieren, insbesondere wenn die Verarbeitung Zeit in Anspruch nehmen kann.

Wenn Sie die übersprungenen Zeilen nicht erneut verarbeiten müssen, sollte es ausreichen, sie einfach zu protokollieren. Eine am Ende des Prozesses gesendete E-Mail mit der Anzahl der übersprungenen Zeilen ist eine angemessene Benachrichtigung.

Andernfalls würde ich eine Beistelltabelle für die Zeilen verwenden, die repariert (und erneut verarbeitet) werden sollen. Diese Beistelltabelle kann entweder eine einfache Referenz (ohne Fremdschlüssel) oder eine vollständige Kopie sein: Letzteres ist, auch wenn es teurer ist, erforderlich, wenn Sie nicht die Zeit haben, das nullProblem zu beheben, bevor Sie die Hauptdaten bereinigen müssen.

Matthieu M.
quelle
-1

Nullen können bei der Übersetzung oder Zuordnung von Datenbanktypen zu Sprachtypen behandelt werden. In C # finden Sie beispielsweise eine generische Methode, die für jeden Typ null für Sie behandelt:

public static T Convert<T>(object obj)
        {
            if (obj == DBNull.Value)
            {
                return default(T);
            }

            return (T) obj;
        }

public static T Convert<T>(object obj, T defaultValue)
        {
            if (obj == DBNull.Value)
            {
                T t = defaultValue;
                return t;
            }

            return (T) obj;
        }

Oder wenn Sie eine Aktion ausführen möchten ...

 public static T Convert<T>(object obj, T defaultValue)
        {
            if (obj == DBNull.Value)
            {
                //Send an Alert, we might want pass in the name
                //of column or other details as well
                SendNullAlert();
                //Set it to default so we can keep processing
                T t = defaultValue;
                return t;
            }

            return (T) obj;
        }

Und dann werden wir in der Zuordnung, in diesem Fall zu einem Objekt vom Typ "Sample", für jede der Spalten null behandeln:

public class SampleMapper : MapperBase<Sample>
    {
        private const string Id = "Id";
        private const string Name = "Name";
        private const string DataValue = "DataValue";
        private const string Created = "Created";

        protected override Sample Map(IDataRecord record)
        {
            return new Sample(
                Utility.Convert<Int64>(record[Id]),
                Utility.Convert<String>(record[Name]),
                Utility.Convert<Int32>(record[DataValue]),
                Utility.Convert<DateTime>(record[Created])
                );
        }
    }

Schließlich können alle Zuordnungsklassen basierend auf der SQL-Abfrage oder den beteiligten Tabellen automatisch generiert werden, indem die SQL-Datentypen betrachtet und in die sprachspezifischen Datentypen übersetzt werden. Dies tun viele ORMs automatisch für Sie. Beachten Sie, dass einige Datenbanktypen möglicherweise keine direkte Zuordnung haben (georäumliche Spalten usw.) und möglicherweise eine spezielle Behandlung erfordern.

Jon Raynor
quelle
Wenn jemand die entsprechende Java-Version veröffentlichen möchte, wäre das großartig ...
Jon Raynor
Ich denke, der Beispielcode ist auch für Java-Entwickler vollkommen verständlich. In meiner Situation habe ich bereits ein ORM eingerichtet, muss also keines implementieren. Ihre Antwort behandelt jedoch nur Standardwerte für Nullen, während in meinem Fall der viel wichtigere Fall darin besteht, eine Null zu erkennen und eine Aktion auszulösen (z. B. einen Administrator über die fehlerhaften Daten zu informieren).
Jhyot
Ahhh, ich werde meine Antwort basierend darauf aktualisieren.
Jon Raynor
Ihr bearbeiteter Code verfügt jetzt über eine Standardaktion für einen beliebigen Nullwert (dh er ist vollständig generisch). Das ist meiner zweiten Option in der ursprünglichen Frage sehr ähnlich, dh wirf einfach null auf und fange sie irgendwo. Aber wie dort angegeben, muss ich die Aktionen danach unterscheiden, welcher Wert fehlt.
Jhyot