Conceptions et pratiques pour se prémunir contre les entrées nulles erronées de la base de données

9

Une partie de mon programme récupère les données de nombreuses tables et colonnes dans ma base de données pour le traitement. Certaines colonnes peuvent l'être null, mais dans le contexte de traitement actuel, c'est une erreur.

Cela ne devrait "théoriquement" pas se produire, donc s'il le fait, cela indique des données incorrectes ou un bogue dans le code. Les erreurs ont différentes gravités, selon le champ null; c'est-à-dire que pour certains champs, le traitement doit être interrompu et que quelqu'un doit en être informé, pour d'autres, le traitement doit être autorisé à se poursuivre et simplement informer quelqu'un.

Existe-t-il de bons principes d'architecture ou de conception pour gérer les nullentrées rares mais possibles ?

Les solutions devraient être possibles à implémenter avec Java mais je n'ai pas utilisé la balise car je pense que le problème est quelque peu indépendant du langage.


Quelques pensées que j'avais moi-même:

Utilisation de NOT NULL

Le plus simple serait d'utiliser une contrainte NOT NULL dans la base de données.

Mais que se passe-t-il si l'insertion originale des données est plus importante que cette étape de traitement ultérieure? Donc, dans le cas où l'insertion mettrait un nulldans la table (soit à cause de bogues, soit d'une raison valable), je ne voudrais pas que l'insertion échoue. Disons que de nombreuses autres parties du programme dépendent des données insérées, mais pas de cette colonne particulière. Je préfère donc risquer l'erreur dans l'étape de traitement actuelle au lieu de l'étape d'insertion. C'est pourquoi je ne veux pas utiliser de contrainte NOT NULL.

Naïvement dépendant de NullPointerException

Je pourrais simplement utiliser les données comme si je m'attendais à ce qu'elles soient toujours là (et cela devrait vraiment être le cas), et attraper les NPE résultants à un niveau approprié (par exemple pour que le traitement de l'entrée actuelle s'arrête mais pas la progression du traitement dans son ensemble) ). C'est le principe du «fail fast» et je le préfère souvent. S'il s'agit d'un bogue au moins, j'obtiens un NPE enregistré.

Mais je perds alors la capacité de différencier les différents types de données manquantes. Par exemple, pour certaines données manquantes, je pourrais les laisser de côté, mais pour d'autres, le traitement devrait être arrêté et un administrateur notifié.

Vérification nullavant chaque accès et levée d'exceptions personnalisées

Les exceptions personnalisées me permettraient de décider de l'action correcte en fonction de l'exception, donc cela semble être la voie à suivre.

Mais si j'oublie de le vérifier quelque part? De plus, j'encombre ensuite mon code avec des contrôles nuls qui ne sont jamais ou rarement attendus (et qui ne font donc certainement pas partie du flux de logique métier).

Si je choisis cette voie, quels modèles conviennent le mieux à l'approche?


Toutes les réflexions et commentaires sur mes approches sont les bienvenus. Aussi de meilleures solutions de toute nature (modèles, principes, meilleure architecture de mon code ou modèles, etc.).

Éditer:

Il y a une autre contrainte, en ce que j'utilise un ORM pour faire le mappage de la base de données à l'objet de persistance, donc faire des vérifications nulles à ce niveau ne fonctionnerait pas (car les mêmes objets sont utilisés dans des parties où le null ne fait aucun mal) . J'ai ajouté cela parce que les réponses fournies jusqu'à présent mentionnaient toutes deux cette option.

jhyot
la source
5
"Certaines colonnes peuvent être nulles, mais dans le contexte de traitement actuel, c'est une erreur. ... au cas où l'insertion mettrait une valeur nulle dans la table, je ne voudrais pas que l'insertion échoue." Ces deux conditions sont contradictoire. Il est impossible de trouver une solution tant que vous n'avez pas assoupli l'une des deux conditions.
Kilian Foth
@KilianFoth Eh bien, ma relaxation est que l'erreur dans le contexte du "traitement en cours" est moins grave que lors de l'insertion. J'accepte donc les rares erreurs de traitement, mais je veux avoir une bonne conception robuste pour les gérer. C'est pourquoi NOT NULL, qui serait sinon une bonne solution, n'est pas possible ici.
jhyot
1
Si vous vous engagez à accepter autant d'erreurs, les auteurs de ces erreurs ne les corrigeront jamais. Si leurs déclarations d'insertion en désordre réussissent, quelle incitation ont-elles jamais à arranger les choses? Considérez-vous que la robustesse n'échoue pas mais accepte les mauvaises données?
Tulains Córdova du
@ user61852 Je n'accepte explicitement pas les erreurs mais je veux les gérer avec élégance. Avaler des pointeurs nuls est hors de question. De plus, que se passe-t-il si ma pièce est vraiment objectivement (telle que définie par l'entreprise) moins importante que de nombreuses autres pièces qui nécessitent l'insertion pour réussir mais ne nécessitent pas que ce champ particulier soit défini? Les insertions ne proviennent pas d'une entrée utilisateur où je pourrais les forcer à ajouter la valeur, mais d'un autre code où l'omission est très probablement un bogue (mais pas assez important pour casser l'insertion).
jhyot
1
Les marquer comme NON NUL dans la base de données serait la meilleure solution, si une colonne est nullable, alors le code devra gérer le cas quand il l'est, même s'il n'est pas attendu car le mécanisme de stockage le permet.
Jon Raynor

Réponses:

9

Je mettrais les vérifications nulles dans votre code de mappage, où vous construisez votre objet à partir du jeu de résultats. Cela place la vérification à un seul endroit et ne permettra pas à votre code de traiter à mi-chemin un enregistrement avant de frapper une erreur. Selon le fonctionnement de votre flux d'application, vous souhaiterez peut-être effectuer le mappage de tous les résultats en tant qu'étape de prétraitement au lieu de mapper et de traiter chaque enregistrement un par un.

Si vous utilisez un ORM, vous devrez effectuer toutes vos vérifications nulles avant de traiter chaque enregistrement. Je recommanderais une recordIsValid(recordData)méthode de type, de cette façon, vous pouvez (encore une fois) garder toute la logique de vérification nulle et de validation en un seul endroit. Je ne voudrais certainement pas mélanger les contrôles nuls avec le reste de votre logique de traitement.

TMN
la source
Merci, c'est une bonne idée! J'utilise en effet un ORM, donc les contrôles à ce niveau ne fonctionneront pas. Mais j'ai également une correspondance avec des objets du domaine réel à partir des objets de persistance. Je vérifierai si la cartographie et la validation dans une étape de prétraitement seraient possibles.
jhyot
Et si vous changez d'ORM, alors quoi? Mieux vaut défendre cela à la source (voir la réponse de Doc Brown).
Robbie Dee
@RobbieDee: Ça ne devrait pas avoir d'importance. Si vous devez réécrire le code de mappage, soit les vérifications nulles sont là et vous les modifiez dans le cadre de la réécriture, soit vous disposez d'une méthode distincte qui effectue les vérifications nulles sur vos objets métier, donc aucune réécriture n'est nécessaire. Et comme le suggère Doc Brown, il est parfois important de noter que des données sont manquantes au lieu de les masquer avec une valeur par défaut.
TMN
Cela devrait se produire plus haut dans le flux ETL. Vous risquez toujours de dupliquer vos efforts de cette façon.
Robbie Dee
6

Il semble que l'insertion d'une valeur nulle soit une erreur, mais vous avez peur d'imposer cette erreur lors de l'insertion, car vous ne voulez pas perdre de données. Cependant, si un champ ne doit pas être nul mais l'est, vous perdez des données . Par conséquent, la meilleure solution consiste à s'assurer que les champs nuls ne sont pas enregistrés par erreur en premier lieu.

À cette fin, assurez-vous que les données sont correctes dans le seul référentiel permanent faisant autorité pour ces données, la base de données. Faites-le en ajoutant des contraintes non nulles. Ensuite, votre code peut échouer, mais ces échecs vous avertissent immédiatement des bogues, vous permettant de corriger les problèmes qui vous font déjà perdre des données. Maintenant que vous pouvez facilement identifier les bogues, testez votre code et testez-le deux fois. Vous serez en mesure de corriger les bogues entraînant une perte de données et, ce faisant, de simplifier considérablement le traitement en aval des données, car vous n'aurez pas à vous soucier des valeurs nulles.

Réintégrer Monica
la source
2
Merci d'avoir répondu. Je suis d'accord que votre solution est la bonne façon de le faire, et vous l'avez formulée de manière concise. Des contraintes en dehors de mon influence peuvent rendre difficile ou impossible (par exemple, les ressources indisponibles pour tester ou pour rendre le code existant automatiquement testable), mais je devrais certainement vérifier si cette solution peut fonctionner avant d'essayer d'autres moyens. Dans ma pensée d'origine, j'ai peut-être supposé trop rapidement que je ne pouvais pas résoudre le problème à la source.
jhyot
@jhyot D'accord. C'est frustrant quand on ne peut pas faire les choses de façon propre. J'espère que ma réponse sera au moins utile à ceux qui ont des problèmes similaires mais qui sont capables d'attaquer la cause profonde au lieu de nettoyer le gâchis après coup.
Rétablir Monica le
5

En ce qui concerne cette phrase dans la question:

Cela ne devrait "théoriquement" pas se produire, donc s'il le fait, cela indique des données incorrectes ou un bogue dans le code.

J'ai toujours apprécié cette citation (gracieuseté de cet article ):

Je trouve amusant quand les programmeurs débutants croient que leur travail principal est d'empêcher les programmes de planter. J'imagine que cet argument d'échec spectaculaire ne serait pas aussi attrayant pour un tel programmeur. Les programmeurs plus expérimentés se rendent compte que le code correct est excellent, le code qui plante peut être amélioré, mais un code incorrect qui ne plante pas est un horrible cauchemar.

Fondamentalement, il semble que vous approuviez la loi de Postel , "soyez conservateur dans ce que vous envoyez, soyez libéral dans ce que vous acceptez". Bien qu'il soit excellent en théorie, dans la pratique, ce «principe de robustesse» conduit à des logiciels qui ne sont pas robustes , du moins à long terme - et parfois à court terme également. (Comparez l'article d'Eric Allman The Robustness Principle Reconsidered , qui est un traitement très approfondi du sujet, bien que principalement axé sur les cas d'utilisation de protocoles de réseau.)

Si vous avez des programmes qui n'insèrent pas correctement des données dans votre base de données, ces programmes sont endommagés et doivent être corrigés . La résolution du problème ne fait que l'empirer; c'est l'équivalent en génie logiciel de permettre à un toxicomane de continuer sa dépendance.

De façon pragmatique, cependant, vous devez parfois permettre au comportement "cassé" de se poursuivre, au moins temporairement, en particulier dans le cadre d'une transition transparente d'un état cassé laxiste à un état strict et correct. Dans ce cas, vous souhaitez trouver un moyen de permettre aux insertions incorrectes de réussir, tout en permettant au magasin de données "canonique" d'être toujours dans un état correct . Il ya différentes manière de faire ceci:

  • Utilisez un déclencheur de base de données pour convertir les insertions incorrectes en insertions correctes, par exemple en remplaçant les valeurs manquantes / nulles par des valeurs par défaut
  • Insérez les programmes incorrects dans une table de base de données distincte qui peut être "incorrecte" et disposez d'un processus planifié distinct ou d'un autre mécanisme qui déplace les données corrigées de cette table vers le magasin de données canoniques.
  • Utilisez le filtrage côté requête (par exemple une vue) pour vous assurer que les données extraites de la base de données sont toujours dans un état correct, même si les données au repos ne sont pas

Une façon de contourner tous ces problèmes consiste à insérer une couche API que vous contrôlez entre les programmes qui émettent des écritures et la base de données réelle.

Il semble qu'une partie de votre problème est que vous ne connaissez même pas tous les endroits qui génèrent des écritures incorrectes - ou qu'il y en a tout simplement trop pour que vous puissiez les mettre à jour. C'est un état effrayant, mais il n'aurait jamais dû se produire en premier lieu.

Dès que vous obtiendrez plus d'une poignée de systèmes autorisés à modifier les données dans un magasin de données de production canonique, vous aurez des ennuis: il n'y a aucun moyen de maintenir centralement quoi que ce soit à propos de cette base de données. Il serait préférable d'autoriser le moins de processus possible à émettre des écritures et à les utiliser en tant que «portiers» qui peuvent prétraiter les données avant de les insérer si nécessaire. Le mécanisme exact pour cela dépend vraiment de votre architecture spécifique.

Daniel Pryden
la source
"Si vous avez des programmes qui n'insèrent pas correctement des données dans votre base de données, ces programmes sont endommagés et doivent être corrigés." c'est génial aussi en théorie, mais la réalité est qu'ils ajouteront toujours des enregistrements pendant que certains comités continuent de débattre de l'utilisation de "NA" ou "None".
JeffO
@JeffO: Aucun comité ne devrait débattre de la nécessité de stocker "NA", "None", NULL ou autre chose dans la base de données. Les parties prenantes non techniques ont intérêt à savoir quelles données sortent de la base de données et comment elles sont utilisées, mais pas dans la représentation interne.
Daniel Pryden
@DanielPryden: Lors de mon dernier emploi, nous avions un comité d'examen de l'architecture (avec un sous-comité DBA) qui examinerait les modifications techniques interdomaines. Très technique, mais ils ne se sont rencontrés que toutes les deux semaines et si vous ne leur fournissiez pas suffisamment de détails, ils différeraient leur décision jusqu'à ce que vous ... lors d'une réunion ultérieure. La plupart des modifications non triviales du système qui ne consistaient pas à ajouter des fonctionnalités par le biais d'un nouveau code prenaient généralement un mois environ.
TMN
@DanielPryden - J'ai participé à des réunions avec le débat de la haute direction sur les étiquettes des zones de texte. Vous pourriez faire valoir que cela n'a rien à voir avec ce que vous allez nommer dans l'application ou la base de données, mais c'est le cas.
JeffO
En réponse aux commentaires sur l'obtention d'approbations supplémentaires pour des modifications de ce type: mon point sur les valeurs étant "incorrectes" présuppose que les valeurs autorisées sont déjà documentées quelque part - c'est pourquoi l'OP dit que ces valeurs doivent être considérées comme un bogue. Si le schéma de la base de données est spécifié pour autoriser une valeur, cette valeur n'est pas un bogue. Le fait est que si vous avez des données qui ne correspondent pas à votre schéma, alors quelque chose est cassé: votre priorité devrait être de faire correspondre les données et le schéma. Selon l'équipe, cela peut impliquer de modifier les données, le schéma ou les deux.
Daniel Pryden
2

" Existe-t-il de bons principes d'architecture ou de conception pour gérer les entrées nulles rares mais possibles? "

Réponse simple - oui.

ETL

Effectuez un traitement initial pour vous assurer que les données sont de qualité suffisante pour entrer dans la base de données. Tout ce qui se trouve dans le fichier de dépôt doit être signalé et toutes les données propres peuvent être chargées dans la base de données.

En tant que quelqu'un qui a été à la fois braconnier (dev) et gardien de jeu (DBA), je sais par expérience amère que les tiers ne résoudront tout simplement pas leurs problèmes de données à moins qu'ils ne soient obligés de le faire. Se pencher constamment en arrière et masser les données à travers crée un dangereux précédent.

Mart / Dépôt

Dans ce scénario, les données brutes sont transmises à la base de données du référentiel, puis une version filtrée est envoyée à la base de données mart à laquelle les applications ont ensuite accès.

Les valeurs par défaut

Si vous pouvez appliquer des valeurs par défaut raisonnables aux colonnes, vous devriez, bien que cela puisse impliquer un certain travail s'il s'agit d'une base de données existante.

Échouer tôt

Il est tentant de simplement résoudre les problèmes de données au niveau de la passerelle vers l'application, la suite de rapports, l'interface, etc. Je vous conseille fortement de ne pas vous fier uniquement à cela. Si vous connectez un autre widget à la base de données, vous serez potentiellement confronté à nouveau aux mêmes problèmes. Traitez les problèmes de qualité des données.

Robbie Dee
la source
+1 C'est ce que je ferais, collecter toutes les données et créer un ensemble de données valide pour votre application à traiter.
Kwebble
1

Chaque fois que votre cas d'utilisation permet de remplacer NULL en toute sécurité par une bonne valeur par défaut, vous pouvez effectuer la conversion dans les SELECTinstructions Sql à l'aide de ISNULLou COALESCE. Donc au lieu de

 SELECT MyColumn FROM MyTable

on peut écrire

 SELECT ISNULL(MyColumn,DefaultValueForMyColumn) FROM MyTable

Bien sûr, cela ne fonctionnera que lorsque l'ORM permettra de manipuler directement les instructions de sélection ou de fournir des modèles modifiables pour la génération. Il faut s'assurer qu'aucune erreur "réelle" n'est masquée de cette façon, donc n'appliquez-la que si le remplacement par une valeur par défaut est exactement ce que vous voulez en cas de NULL.

Si vous pouvez modifier la base de données et le schéma, et que votre système db le prend en charge, vous pouvez envisager d'ajouter une clause de valeur par défaut aux colonnes spécifiques, comme suggéré par @RobbieDee. Cependant, cela nécessitera également de modifier les données existantes dans la base de données pour supprimer toutes les valeurs NULL précédemment insérées, et cela supprimera la possibilité de distinguer entre les données d'importation correctes et incomplètes par la suite.

D'après ma propre expérience, je sais que l'utilisation d'ISNULL peut étonnamment bien fonctionner - dans le passé, je devais maintenir une application héritée où les développeurs d'origine avaient oublié d'ajouter des contraintes NOT NULL à de nombreuses colonnes, et nous ne pouvions pas facilement ajouter ces contraintes plus tard pour quelques raisons. Mais dans 99% de tous les cas, 0 par défaut pour les colonnes de nombres et la chaîne vide par défaut pour les colonnes de texte était tout à fait acceptable.

Doc Brown
la source
Pendant que cela fonctionne, vous pouvez finir par devoir dupliquer le code défensif pour chaque SELECT. Une bien meilleure approche consiste à définir une valeur par défaut pour une colonne lorsqu'un NULL est inséré, bien que cela ne soit pas possible / souhaitable pour diverses raisons.
Robbie Dee
@RobbieDee: merci pour cette remarque, j'ai changé ma réponse en conséquence. Cependant, si c'est "bien mieux", c'est discutable. Lorsque le code CRUD est au même endroit, le code défensif en double peut ne pas poser beaucoup de problèmes. Et si ce n'est pas le cas, il y a déjà une certaine duplication de code au préalable.
Doc Brown
Les opérations CRUD simples sont bien sûr l'idéal. Mais dans le monde réel, les systèmes ont souvent des vues d'interface utilisateur complexes, des assistants de données générés par l'utilisateur, des rapports, etc. Ce que vous avez décrit pourrait être préférable dans un développement de friches industrielles.
Robbie Dee
Meilleure réponse. Les nouvelles applications ajoutent généralement de nouvelles données qui peuvent être hors de votre contrôle. Les valeurs NULL erronées proviennent généralement de l'importation de données héritées dans des bases de données repensées. Les contraintes sont désactivées pour cela pour lui permettre de se terminer en quelques heures au lieu de plusieurs jours. «Le grand échec» survient souvent lorsque les administrateurs de base de données tentent de réactiver les contraintes. Comme cela n'a jamais été prévu, la direction rechigne souvent aux semaines de travail souvent nécessaires pour corriger les mauvaises données, donc cela reste. Toutes les applications doivent gérer correctement les valeurs NULL en insérant les valeurs par défaut et en signalant ou en invitant les données manquantes dans le cas contraire.
DocSalvager
1

L'OP suppose une réponse qui associe les règles métier aux détails techniques de la base de données.

Cela ne devrait "théoriquement" pas se produire, donc s'il le fait, cela indique des données incorrectes ou un bogue dans le code. Les erreurs ont des degrés de gravité différents, selon le champ qui est nul; c'est-à-dire que pour certains champs, le traitement doit être interrompu et que quelqu'un doit être notifié, pour d'autres, le traitement doit être autorisé à se poursuivre et simplement informer quelqu'un.

Ce sont toutes des règles commerciales. Les règles commerciales ne se soucient pas de nullité en soi. Pour tout ce qu'il sait, la base de données pourrait avoir null, 9999, "BOO!" ... C'est juste une autre valeur. Que, dans un SGBDR, null a des propriétés intéressantes et des utilisations uniques est sans objet.

La seule chose qui compte, c'est ce que la "nullité" signifie pour le ou les objets métier donnés ...

Existe-t-il de bons principes d'architecture ou de conception pour gérer les entrées nulles rares mais possibles?

Oui.

  • Mettez les règles métier dans les classes.
  • La translittération doit se faire dans une couche de code appropriée découplant les classes métier et le magasin de données. Si vous ne pouvez pas le mettre dans le code ORM, au moins ne le mettez pas dans la base de données.
  • Rendez la base de données aussi stupide que possible, pas de règles commerciales ici. Même des choses inoffensives comme la valeur par défaut d'une valeur vous mordront . Été là.
  • Validez les données entrant et sortant de la base de données. Et bien sûr, cela se fait dans le contexte des objets métier.

Lancer une exception lors de la récupération des données n'a pas de sens.

La question est "dois-je stocker de" mauvaises "données"? Ça dépend:

  • De mauvaises données peuvent être utilisées - N'enregistrez jamais des objets non valides ou des objets composites. Des relations complexes entre les données et les entreprises partout. Les utilisateurs peuvent exécuter n'importe quelle fonction à un moment donné, éventuellement en utilisant cette entité commerciale dans un certain nombre de contextes. L'effet (le cas échéant) des mauvaises données, au moment de leur enregistrement, n'est pas connu car il dépend fortement de leur utilisation future. Il n'y a pas de processus unifié / unique de ces données.
  • Ne peut pas progresser s'il y a de mauvaises données - Autoriser l'enregistrement de mauvaises données. Cependant, la prochaine étape d'un processus ne peut pas continuer tant que tout n'est pas valide. Par exemple, faire ses impôts sur le revenu. Lorsqu'il est extrait de la base de données, le logiciel signale les erreurs et ne peut pas être soumis à l'IRS sans vérification de validité.
radarbob
la source
0

Il existe de nombreuses façons de gérer les valeurs nulles, nous allons donc passer de la couche de base de données à la couche d'application.


Couche de base de données

Vous pouvez interdire les null ; bien qu'ici ce ne soit pas pratique.

Vous pouvez configurer une valeur par défaut par colonne:

  • il requiert que la colonne soit absente du insert, donc ne couvre pas l'insertion nulle explicite
  • il empêche la détection des lignes où la insertcolonne a manqué par erreur

Vous pouvez configurer un déclencheur , de sorte qu'à l'insertion, les valeurs manquantes soient automatiquement calculées:

  • il nécessite que les informations nécessaires pour effectuer ce calcul soient présentes
  • cela va ralentir la insert

Couche de requête

Vous pouvez ignorer les lignes où un inconvénient nullest présent:

  • il simplifie la logique principale
  • il empêche de détecter les "mauvaises lignes", donc un autre processus serait nécessaire pour les vérifier
  • cela nécessite que chaque requête soit instrumentée

Vous pouvez fournir une valeur par défaut dans la requête:

  • il simplifie la logique principale
  • il empêche de détecter les "mauvaises lignes", donc un autre processus serait nécessaire pour les vérifier
  • cela nécessite que chaque requête soit instrumentée

Remarque: l'instrumentation de chaque requête n'est pas nécessairement un problème si vous disposez d'un moyen automatisé de les générer.


Couche d'application

Vous pouvez pré-vérifier le tableau pour les interdits null:

  • il simplifie la logique principale
  • il améliore le délai de défaillance
  • cela nécessite de maintenir la logique de pré-vérification et d'application cohérente

Vous pouvez interrompre le traitement lorsque vous rencontrez un interdit null:

  • cela évite de dupliquer la connaissance des colonnes qui peuvent être nullet de celles qui ne peuvent pas
  • c'est encore relativement simple (juste un check + return / throw)
  • cela nécessite que votre processus puisse reprendre (si vous avez déjà envoyé un e-mail, ne voulez pas l'envoyer deux fois, ou cent fois!)

Vous pouvez sauter la ligne lorsque vous rencontrez un interdit null:

  • cela évite de dupliquer la connaissance des colonnes qui peuvent être nullet de celles qui ne peuvent pas
  • c'est encore relativement simple (juste un check + return / throw)
  • il ne nécessite pas que votre processus puisse être repris

Vous pouvez envoyer une notification lorsque vous rencontrez une interdiction null, soit une à la fois, soit par lot, ce qui est complémentaire aux autres méthodes présentées ci-dessus. Cependant, ce qui importe le plus, c'est "et alors?" en cours de retraitement.


Compte tenu de votre situation, je gérerais la situation au niveau de l'application et combinerais soit:

  • interrompre et notifier
  • sauter et notifier

J'aurais tendance à simplement sauter si possible pour garantir en quelque sorte un minimum de progrès, surtout si le traitement peut prendre du temps.

Si vous n'avez pas besoin de retraiter les lignes ignorées, alors simplement les enregistrer devrait être suffisant et un e-mail envoyé à la fin du processus avec le nombre de lignes ignorées sera une notification appropriée.

Sinon, j'utiliserais une table d'appoint pour les lignes à corriger (et à retraiter). Cette table d'appoint peut être soit une simple référence (sans clé étrangère), soit une copie complète: cette dernière, même si elle est plus chère, est nécessaire si vous n'avez pas le temps de vous en occuper nullavant de devoir nettoyer les données principales.

Matthieu M.
la source
-1

Les valeurs nulles peuvent être gérées lors de la traduction ou du mappage des types de base de données en types de langue. Par exemple en C #, voici une méthode générique qui gère null pour vous pour tout type:

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;
        }

Ou, si vous souhaitez effectuer une action ...

 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;
        }

Et puis dans le mappage, dans ce cas à un objet de type "Sample", nous traiterons null pour n'importe laquelle des colonnes:

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])
                );
        }
    }

Enfin, toutes les classes de mappage peuvent être générées automatiquement en fonction de la requête SQL ou des tables impliquées en examinant les types de données SQL et en les convertissant en types de données spécifiques au langage. C'est ce que de nombreux ORM font pour vous automatiquement. Notez que certains types de bases de données peuvent ne pas avoir de mappage direct (colonnes géospatiales, etc.) et peuvent nécessiter une gestion spéciale.

Jon Raynor
la source
Si quelqu'un veut publier la version Java équivalente, ce serait génial ...
Jon Raynor
Je pense que l'exemple de code est parfaitement compréhensible également pour les développeurs Java. Dans ma situation, j'ai déjà un ORM en place, donc je n'ai pas besoin de l'implémenter. Mais votre réponse ne concerne que les valeurs par défaut pour les valeurs nulles, alors que dans mon cas, le cas le plus important est en fait la détection d'une valeur nulle et le déclenchement d'une action (par exemple, informer un administrateur des données erronées).
jhyot
Ahhh, je mettrai à jour ma réponse sur cette base.
Jon Raynor
Votre code modifié a maintenant une action par défaut pour toute valeur nulle (c'est-à-dire qu'il est complètement générique). C'est très similaire à ma 2ème option dans la question d'origine, c'est-à-dire qu'il suffit de lancer null et de l'attraper quelque part. Mais comme indiqué ici, je dois différencier les actions en fonction de la valeur manquante.
jhyot