.net - que - qué es el manejo de excepciones
¿Captura excepciones como el control de flujo de ejecución del programa esperado? (8)
Atrapar la SqlException específica es lo correcto. Este es el mecanismo por el cual SQL Server comunica la condición de clave externa. Incluso si puede preferir un uso diferente del mecanismo de excepción, así es como lo hace SQL Server.
Además, durante el control de las cuatro tablas, es posible que otro usuario agregue un registro relacionado antes de que se complete el control, pero después de leer esa tabla.
Siempre sentí que esperaba que se lanzaran excepciones regularmente y usarlas como lógica de flujo era algo malo. Las excepciones se sienten como que deberían ser, bueno, la " excepción ". Si está esperando y planeando una excepción, eso parece indicar que su código debe ser refactorizado, al menos en .NET ...
Sin embargo. Un escenario reciente me dio una pausa. Publiqué esto en msdn hace un tiempo, pero me gustaría generar más discusión al respecto y este es el lugar perfecto.
Por lo tanto, supongamos que tiene una tabla de base de datos que tiene una clave externa para varias otras tablas (en el caso que originalmente generó el debate, había 4 claves externas que lo señalaban). Desea permitir que el usuario elimine, pero solo si NO hay referencias de clave externa; NO quieres eliminar en cascada.
Normalmente solo hago una verificación para ver si hay referencias, y si las hay, informo al usuario en lugar de hacer la eliminación. Es muy fácil y relajante escribir eso en LINQ, ya que las tablas relacionadas son miembros del objeto, por lo que Section.Projects y Section.Categories y demás es bueno escribir con intellisense y todo ...
Pero el hecho es que LINQ debe presionar potencialmente las 4 tablas para ver si hay filas de resultados apuntando a ese registro, y golpear la base de datos es obviamente una operación relativamente cara.
El líder de este proyecto me pidió que lo cambiara para capturar una SqlException con un código de 547 (restricción de clave externa) y tratarlo de esa manera.
Yo era...
resistente .
Pero en este caso, es mucho más eficiente tragarse la sobrecarga relacionada con la excepción que tragarse los 4 hits de la tabla ... Especialmente porque tenemos que hacer el chequeo en todos los casos, pero se nos ahorra la excepción en el caso cuando no hay niños ...
Además, la base de datos debería ser la responsable de manejar la integridad referencial, ese es su trabajo y lo hace bien ...
Entonces ellos ganaron y yo lo cambié.
Sin embargo, en cierto modo, aún me parece mal .
¿Qué piensan ustedes acerca de esperar y manejar intencionalmente las excepciones? ¿Está bien cuando parece que será más eficiente que consultar de antemano? ¿Es más confuso para el próximo desarrollador que mira su código o menos confuso? ¿Es más seguro, ya que la base de datos podría conocer nuevas restricciones de clave externa que el desarrollador podría no pensar en agregar un cheque? ¿O es una cuestión de perspectiva sobre qué es exactamente lo que crees que es la mejor práctica?
Buena pregunta. Sin embargo, creo que las respuestas ... ¡aterradoras!
Una excepción es un tipo de GOTO.
No me gusta usar excepciones de esta manera porque eso lleva al código de spaghetti.
Simple como eso.
Creo que tiene razón, las excepciones solo deben usarse para manejar resultados inesperados , aquí está usando una excepción para lidiar con un posible resultado esperado, debe tratar este caso de manera explícita pero aun así detectar la excepción para mostrar un posible error.
A menos que esta sea la forma en que se maneja este caso en todo el código, me pondría del lado de usted. El problema de rendimiento solo debería plantearse si es realmente un problema, es decir, dependería del tamaño de esas tablas y del número de veces que se utiliza esta función.
Guau,
En primer lugar, ¿pueden por favor destilar la pregunta un poco, mientras que fue agradable leer una pregunta bien pensada y explicada, que fue bastante para digerir.
La respuesta corta es "sí", pero puede depender.
- Tenemos algunas aplicaciones en las que tenemos mucha lógica empresarial ligada a las consultas SQL (¡no a mi diseño Gov!). Si así es como está estructurado, la administración puede ser difícil de convencer de lo contrario ya que "ya funciona".
- En esta situación, ¿realmente hace un gran problema? Ya que sigue siendo un viaje por el cable y la parte posterior. ¿El servidor hace mucho antes de darse cuenta de que no puede continuar (es decir, si hay una secuencia de transacciones que tienen lugar en su acción, ¿se cae a la mitad, perdiendo tiempo?).
- ¿Tiene sentido hacer el control en la IU primero? ¿Ayuda con tu aplicación? Si proporciona una experiencia de usuario más agradable? (es decir, he visto casos en los que paso por varios pasos en un asistente, comienza, luego se cae, cuando tenía toda la información que necesitaba para caer después del paso 1).
- ¿La concurrencia es un problema? ¿Es posible que el registro se elimine / edite o lo que sea antes de que se realice la confirmación (como en el
File.Exists
clásicoFile.Exists
boo-boo).
En mi opinión:
Haría ambas cosas . Si puedo fallar rápido y proporcionar una mejor experiencia de usuario, genial. Cualquier excepción esperada de SQL (o cualquier otra) debería ser atrapada y alimentada apropiadamente de todos modos.
Sé que hay un consenso de que las excepciones no se deben usar para otras circunstancias excepcionales , pero recuerde que estamos cruzando los límites de las aplicaciones aquí, no esperamos nada . Como dije, esto es como el File.Exists
. File.Exists
, no tiene sentido, se puede eliminar antes de acceder de todos modos.
No hay nada malo con lo que estás haciendo. Las excepciones no son necesariamente "excepcionales". Existen para permitir que los objetos que llaman tengan un control de errores de grano fino según sus necesidades.
No me gusta ver excepciones en ningún lugar de un programa, pero en este caso usaría el mecanismo de excepción.
Incluso si prueba en LINQ, tendrá que atrapar la excepción en caso de que alguien inserte un registro secundario mientras prueba integridad con LINQ. Como debe verificar la excepción de todos modos, ¿por qué duplicar el código?
Otro punto es que este tipo de excepción de "corto alcance" no causa problemas de mantenimiento, ni hace que su programa sea más difícil de leer. Tendrá la oportunidad, la llamada SQL para eliminar y la captura, todo eso dentro de 10 líneas de código, juntas. La intención es obvia.
No es como lanzar una excepción que sea atrapada 5 llamadas de procedimiento en la parte superior de la pila, con los problemas de estar seguro de que todos los objetos intermedios se han cuidado (liberado) correctamente.
Las excepciones no siempre son una respuesta mágica, pero no me sentiría mal usarlas en esta situación.
Mis dos centavos,
Yves
Recomiendo llamar a un procedimiento almacenado que comprueba si hay alguna dependencia, luego elimina si no hay ninguna. De esa forma, se realiza el control de la integridad.
Por supuesto, es probable que desee un procedimiento almacenado diferente para eliminaciones individuales frente a eliminación por lotes ... La eliminación por lotes podría buscar filas secundarias y devolver un conjunto de registros que no eran elegibles para una eliminación masiva (tenía filas secundarias) .
Tu ventaja es absolutamente correcta. Las excepciones no son solo por una vez en una situación de luna azul, sino específicamente para informar resultados que no sean los esperados.
En este caso, la verificación de la clave externa aún se llevaría a cabo, y las excepciones son el mecanismo por el cual se le puede notificar.
Lo que NO deberías hacer es atrapar y suprimir excepciones con una declaración global general. Hacer el manejo de excepciones detallado es específicamente el motivo por el cual se diseñaron excepciones en primer lugar.