2008-09-25 7 views
11

Siempre sentí que esperaba que se lanzaran excepciones de manera regular 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 foránea para varias otras tablas (en el caso que originalmente provocó el debate, había 4 claves externas apuntando a ella). Desea permitir que el usuario elimine, pero solo si NO hay referencias de clave externa; NO quieres eliminar en cascada.
Normalmente solo hago una comprobación para ver si hay referencias, y si las hay, informo al usuario en lugar de hacer la eliminación. Escribir en LINQ es muy fácil y relajante, 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 entonces tiene que golpear potencialmente las 4 tablas para ver si hay alguna fila de resultados apuntando a ese registro, y golpear la base de datos es obviamente una operación relativamente cara.

El líder en 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.

Estaba ...
resistente.

Pero en este caso, es probablemente mucho más eficiente tragarse la sobrecarga relacionada con la excepción que tragar los 4 hits de la tabla ... Especialmente porque tenemos que hacer el control en todos los casos, pero nos ahorramos el 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 ...
Así que ganaron y yo lo cambié.

En algún nivel todavía se siente mal sin embargo.

¿Qué piensan ustedes acerca de esperar y tratar 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?
¿Captura excepciones como el control de flujo de ejecución del programa esperado?

Respuesta

4

Wow,

En primer lugar, puede usted por favor destilar la pregunta un poco, mientras que era agradable para leer un bien pensado y pregunta explicado, que era bastante mucho para digerir.

La respuesta abreviada 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 es un gran problema? Ya que sigue siendo un viaje por el cable y viceversa. ¿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).
  • ¿Es la concurrencia 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 clásico File.Exists boo-boo).

En mi opinión:

que haría tanto . 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.

Yo sé que hay un consenso de que las excepciones no deben ser utilizados para otra cosa que circunstancias excepcionales, pero recuerda, estamos cruzando los límites de aplicación aquí, esperar nada. Como dije, esto es como el File.Exists, no tiene sentido, se puede eliminar antes de acceder de todos modos.

+0

Es una aplicación a muy pequeña escala; en el entorno actual del cliente, la mayor parte de la inserción será realizada por una sola persona. En max hay creo que 25 usuarios. Así que la concurrencia no es un problema, el rendimiento no es un problema, es un momento perfecto para debatir los estándares;) – Grank

+0

Pero no se trata solo de rendimiento o concurrencia. Es la suposición de que ese es el problema. Como dije, haga ambas cosas si proporciona una mejor experiencia de usuario, pero debería manejar excepciones en ambos casos. –

7

Su 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 se debe hacer es capturar y suprimir excepciones con una declaración general de cobertura. Hacer el manejo de excepciones detallado es específicamente el motivo por el cual se diseñaron excepciones en primer lugar.

+0

Bueno, es el resultado esperado, ese es el problema. Muy a menudo, habrá niños. – Grank

+0

Estoy muy de acuerdo con su edición. Específicamente, solo la SqlException 547 está siendo detectada – Grank

+1

Totalmente de acuerdo con usted en este levik, las personas que responden con estas "circunstancias excepcionales" están perdiendo el sentido (ver mi publicación). –

1

No hay nada malo con lo que está 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.

2

Creo que tiene razón, las excepciones solo se deben usar para manejar resultados inesperados, aquí está utilizando una excepción para tratar con un posible resultado esperado, debe tratar este caso explícitamente pero aún atrapar 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, yo estaría de su lado. 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.

1

La captura de 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.

1

Recomiendo llamar a un procedimiento almacenado que comprueba si hay alguna dependencia, y 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 de singleton frente a eliminación de lotes ... La eliminación de lotes podría buscar filas secundarias y devolver un conjunto de registros que no eran elegibles para una eliminación masiva (tenía filas de niños).

2

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.

+0

+1 para el GOTO! eso es tan cierto –

1

No me gusta ver excepciones en cualquier parte de un programa, pero en este caso utilizaría el mecanismo de excepción.

Incluso si prueba en LINQ, tendrá que detectar 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 es atrapada 5 llamadas de procedimiento en la parte superior de la pila, con el problema de estar seguro de que todos los objetos intermedios se han tenido en cuenta (liberados) 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

Cuestiones relacionadas