¿Cómo manejar las infracciones de restricciones de db en la interfaz de usuario?
Implementamos la mayoría de nuestras reglas de negocio en la base de datos, utilizando procedimientos almacenados.
Nunca puedo decidir la mejor manera de pasar los errores de violación de restricción de datos de la base de datos a la interfaz de usuario. Las restricciones de las que hablo están más relacionadas con las reglas de negocios que con la integridad de los datos.
Por ejemplo, un error de base de datos como "No se puede insertar una fila de claves duplicadas" es lo mismo que la regla empresarial "no se puede tener más de un Foo con el mismo nombre". Pero lo "implementamos" en la ubicación de sentido más común: como una restricción única que arroja una excepción cuando se viola la regla.
Otras reglas como "Solo se le permiten 100 Foos por día" no causan errores por decir, ya que se manejan con gracia mediante un código personalizado comoreturn empty dataset
que el código de la aplicación comprueba y devuelve a la capa de interfaz de usuario.
Y ahí está el problema. Nuestro código de interfaz de usuario se ve así (este es el código de servicios web AJAX.NET, pero cualquier marco ajax funcionará):
WebService.AddFoo("foo", onComplete, onError); // ajax call to web service
function onComplete(newFooId) {
if(!newFooId) {
alert('You reached your max number of Foos for the day')
return
}
// update ui as normal here
}
function onError(e) {
if(e.get_message().indexOf('duplicate key')) {
alert('A Foo with that name already exists');
return;
}
// REAL error handling code here
}
(Como nota al margen: noto que esto es lo que hace stackoverflow cuando envía comentarios demasiado rápido: el servidor genera unaHTTP 500
respuesta y la interfaz de usuario lo detecta.)
omo puede ver, estamos manejando las infracciones de las reglas de negocios en dos lugares aquí, uno de los cuales (es decir, el error de seguridad único) se maneja como un caso especial para el código que se supone que manejarea errores (no infracciones de las reglas de negocio), ya que .NET propaga excepciones hasta elonError()
manejador.
Esto se siente mal. Mis opciones creo que son:
catch la excepción de 'violación de clave duplicada' en el nivel del servidor de aplicaciones yconverti it to sea lo que sea que la interfaz de usuario espera a medida que la bandera "viola la regla de negocios",adelantarse el error (digamos, con un"select name from Foo where name = @Name"
) y devolver lo que sea que el servidor de aplicaciones espera como bandera de "violación de la regla de negocios",en el mismo estadio que 2): aproveche la restricción única incorporada en la capa de base de datos y ciegamenteinsert into Foo
, detectando cualquier excepción y conviértela a lo que sea que el servidor de aplicaciones espera a medida que la bandera "viola la regla de negocios"blindlyinsert into Foo
(como 3) y deje que esa Excepción se propague a la interfaz de usuario,má haga que el servidor de aplicaciones aumente las infracciones de las reglas comerciales comoExceptions
(en oposición a 1). De esta forma, TODOS los errores se manejan en la capa de interfaz de usuarioonError()
(o similar) código.Lo que me gusta de 2) y 3) es que las infracciones de las reglas comerciales se "arrojan" donde se implementan: en el proceso almacenado. Lo que no me gusta de 1) y 3) es Ipensa involucran cheques estúpidos como"if error.IndexOf('duplicate key')"
, al igual que lo que está en la capa de interfaz de usuario actualmente.
Edita: Me gusta 4), pero la mayoría de la gente dice que useException
s solo enexcepciona circunstancias.
Entonces, ¿cómo manejan ustedes la propagación de las infracciones de las reglas comerciales hasta la interfaz de usuario con elegancia?