Question

J’ai toujours pensé que s’attendre à ce que des exceptions soient lancées régulièrement et à les utiliser comme logique de flux était une mauvaise chose. Les exceptions donnent l’impression qu’elles devraient être, eh bien, l’expression " exception ". Si vous attendez et planifiez une exception, cela semblerait indiquer que votre code doit être refactorisé, du moins dans .NET ...
Toutefois. Un scénario récent m'a donné une pause. J'ai posté ceci sur msdn il y a un moment, mais j'aimerais générer plus de discussions à ce sujet et c'est l'endroit idéal!

Donc, disons que vous avez une table de base de données qui a une clé étrangère pour plusieurs autres tables (dans le cas qui a initialement incité le débat, il y avait 4 clés étrangères qui la pointaient). Vous souhaitez autoriser l'utilisateur à supprimer, mais uniquement s'il n'y a PAS de références de clé étrangère; vous ne voulez pas supprimer en cascade.
Normalement, je vérifie simplement s'il y a des références et, le cas échéant, j'en informe l'utilisateur au lieu de supprimer. Il est très facile et relaxant d'écrire que dans LINQ, les tables liées sont des membres de l'objet, donc Section.Projects et Section.Categories et cetera sont agréables à taper avec intellisense et tout ...
Mais le fait est que LINQ doit alors toucher potentiellement les 4 tables pour voir s’il existe des lignes de résultats pointant vers cet enregistrement, et toucher la base de données est évidemment toujours une opération relativement coûteuse.

Le responsable de ce projet m'a demandé de le modifier pour qu'il intercepte simplement une exception SqlException avec un code de 547 (contrainte de clé étrangère) et le traite de cette façon.

J'étais ...
résistant .

Mais dans ce cas, il est probablement beaucoup plus efficace d'avaler les frais généraux liés à l'exception que d'avaler les 4 hits de table ... D'autant plus que nous devons faire le contrôle dans tous les cas, mais nous épargnons l'exception dans le cas quand il n'y a pas d'enfants ...
De plus, la base de données devrait être la personne responsable de la gestion de l’intégrité référentielle, c’est son travail et elle le fait bien ...
Alors ils ont gagné et je l'ai changé.

À un certain niveau, cela me semble toujours faux .

Que pensez-vous de l'attente et du traitement intentionnel des exceptions? Est-ce que ça va quand il semble que ce sera plus efficace que de vérifier à l'avance? Est-ce plus déroutant pour le prochain développeur qui examine votre code, ou moins déroutant? Est-il plus sûr, étant donné que la base de données pourrait connaître de nouvelles contraintes de clé étrangère que le développeur pourrait ne pas penser à ajouter une vérification? Ou est-ce une question de perspective sur ce que vous pensez être la meilleure pratique?

Était-ce utile?

La solution

Wow,

Tout d’abord, pouvez-vous résumer un peu la question, même si c’était agréable de lire une question bien pensée et bien expliquée, c’était beaucoup à digérer.

La réponse courte est "oui", mais cela peut dépendre.

  • Nous avons certaines applications pour lesquelles nous avons beaucoup de logique métier liée aux requêtes SQL (pas ma conception Gov!). Si tel est le cas, il peut être difficile de convaincre la direction de l’autre car elle "fonctionne déjà".
  • Dans cette situation, cela fait-il vraiment une grosse affaire? Comme c'est toujours un voyage sur le fil et le retour. Le serveur fait-il beaucoup avant de se rendre compte qu'il ne peut plus continuer (c.-à-d. Si une séquence de transactions se produit dans votre action, est-ce que ce dernier tombe à mi-chemin et vous fait perdre du temps?).
  • Est-il judicieux de commencer par vérifier l'interface utilisateur? Cela vous aide-t-il avec votre application? S'il offre une expérience utilisateur plus agréable? (c’est-à-dire que j’ai vu des cas où vous exécutez plusieurs étapes dans un assistant, celui-ci commence, puis s’effondre, il contient toutes les informations nécessaires pour s’effondrer après l’étape 1).
  • La concurrence d'accès est-elle un problème? Est-il possible que l'enregistrement soit supprimé / édité ou quoi que ce soit avant que votre commit ait lieu (comme dans le classique File.Exists boo-boo).

À mon avis:

Je referais les deux . Si je peux échouer rapidement et fournir une meilleure expérience utilisateur, tant mieux. Les exceptions SQL (ou autres) attendues doivent être interceptées et renvoyées de manière appropriée.

Je sais qu'il existe un consensus sur le fait que les exceptions ne doivent pas être utilisées dans des circonstances exceptionnelles , mais rappelez-vous, nous dépassons les limites des applications ici, n'attendons rien . Comme je l'ai dit, cela ressemble à File.Exists , cela ne sert à rien, il peut être supprimé avant que vous n'y accédiez quand même.

Autres conseils

Votre avance est absolument juste. Les exceptions ne sont pas une seule fois dans une situation de lune bleue, mais spécifiquement pour signaler des résultats autres que ceux escomptés.

Dans ce cas, la vérification de la clé étrangère aurait toujours lieu et le mécanisme par lequel vous pouvez être averti constitue une exception.

Ce que vous ne devriez PAS faire, c’est capturer et supprimer les exceptions avec une instruction capturante globale. La gestion précise des exceptions est précisément la raison pour laquelle les exceptions ont été conçues en premier lieu.

Je pense que vous avez raison, les exceptions ne doivent être utilisées que pour gérer les résultats inattendus . Dans ce cas, vous utilisez une exception pour traiter un résultat éventuellement attendu. Vous devez traiter ce cas explicitement, l'exception pour afficher une erreur possible.

À moins que cette affaire ne soit traitée comme telle tout au long du code, je me rangerais avec vous. Le problème de performance ne doit être soulevé que s’il s’agit d’un problème, c’est-à-dire que cela dépend de la taille de ces tables et du nombre d'utilisations de cette fonction.

Belle question. Cependant, je trouve les réponses ... effrayantes!
Une exception est une sorte de GOTO.
Je n'aime pas utiliser les exceptions de cette manière car cela conduit au code spaghetti.
Aussi simple que cela.

Il n'y a rien de mal à ce que vous faites. Les exceptions ne sont pas nécessairement "exceptionnelles". Ils existent pour permettre aux objets appelants d’avoir une gestion des erreurs plus fine en fonction de leurs besoins.

Catching the SqlException spécifique est la bonne chose à faire. C'est le mécanisme par lequel SQL Server communique la condition de clé étrangère. Même si vous préférez une utilisation différente du mécanisme des exceptions, voici comment SQL Server le fait.

En outre, lors de la vérification des quatre tables, un autre utilisateur peut ajouter un enregistrement associé avant la fin de la vérification mais après avoir lu cette table.

Je vous recommande d'appeler une procédure stockée qui vérifie s'il existe des dépendances, puis supprime s'il en existe. De cette façon, la vérification de l'intégrité est effectuée.

Bien sûr, vous souhaiterez probablement une procédure stockée différente pour les suppressions singleton par rapport à la suppression par lots ... La suppression par lots pourrait rechercher des lignes enfants et renvoyer un ensemble d'enregistrements non admissibles à une suppression en bloc ( lignes enfants).

Je n'aime pas voir les exceptions partout dans un programme, mais dans ce cas, j'utiliserais le mécanisme des exceptions.

Même si vous testez dans LINQ, vous devrez capturer l'exception si quelqu'un insère un enregistrement enfant pendant que vous testez l'intégrité avec LINQ. Puisque vous devez quand même vérifier l’exception, pourquoi dupliquer le code?

Un autre point est que ce type de "courte portée" exception ne cause pas de problèmes de maintenance, ni rend votre programme plus difficile à lire. Vous aurez la tentative, l'appel SQL à supprimer et la capture, tout cela dans 10 lignes de code, ensemble. L'intention est évidente.

Pas comme si vous lançiez une exception à capturer 5 appels de procédure plus haut dans la pile, avec les problèmes de s’assurer que tous les objets entre les deux ont été pris en charge (libérés) correctement.

Les exceptions ne sont pas toujours une réponse magique, mais je ne me sentirais pas dans l’erreur de les utiliser dans cette situation.

Mes deux cents,

Yves

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top