Мы реализуем большинство наших бизнес-правил в базе данных, используя хранимые процедуры.
Я не могу решить, как лучше передать ошибки нарушения ограничений данных из базы данных обратно в пользовательский интерфейс. Ограничения, о которых я говорю, связаны больше с бизнес-правилами, чем с целостностью данных.
Например, ошибка db, такая как "Невозможно вставить повторяющуюся строку ключа", совпадает с бизнес-правилом "у вас не может быть более одного Foo с тем же именем". Но мы "реализовали" его в наиболее распространенном смысле: как уникальное ограничение, которое генерирует исключение, когда правило нарушается.
Другие правила, такие как "Вам разрешено только 100 футов в день", не вызывают ошибок за один раз, поскольку они грациозно обрабатываются специальным кодом, например return empty dataset
, который код приложения проверяет и передает обратно слой ui.
И в этом есть руб. Наш код ui выглядит так (это код веб-сервисов AJAX.NET, но любая инфраструктура ajax будет делать):
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
}
(В качестве примечания: Я замечаю, что это то, что делает stackoverflow, когда вы отправляете комментарии слишком быстро: сервер генерирует ответ HTTP 500
, и ui его ловит.)
Итак, вы видите, что мы обрабатываем нарушения бизнес-правил в двух местах здесь, один из которых (то есть уникальная ошибка constaint) обрабатывается как особый случай для кода, который должен обрабатывать реальные ошибки (а не нарушения бизнес-правил), так как .NET распространяет Исключения полностью до обработчика onError()
.
Это кажется неправильным. Мои варианты, я думаю:
- поймайте исключение "дублирующее ключевое нарушение" на уровне сервера приложений и преобразуйте его во все, что ожидает ui, как флаг "бизнес-правила нарушен" ,
- вытеснить ошибку (например, с помощью
"select name from Foo where name = @Name"
) и вернуть все, что сервер приложений ожидает, поскольку флаг "бизнес-правила нарушен" , - в том же балласте, что и 2): используйте уникальное ограничение, встроенное в слой db, и слепо
insert into Foo
, перехватывая любые исключения и преобразовывая его во все, что сервер приложений ожидает в качестве флага "бизнес-правила нарушен" - вслепую
insert into Foo
(например, 3) и пусть это исключение распространяется на ui, плюс сервер приложений поднимает нарушения бизнес-правил как реальныеExceptions
(в отличие от 1). Таким образом, ВСЕ ошибки обрабатываются в слое ui layeronError()
(или аналогичном).
То, что мне нравится в 2) и 3), заключается в том, что нарушения бизнес-правил "брошены" там, где они реализованы: в сохраненной proc. Что мне не нравится в 1) и 3), я думаю, что они включают в себя глупые проверки, такие как "if error.IndexOf('duplicate key')"
, как и то, что сейчас находится в слое ui.
Изменить: мне нравится 4), но большинство людей говорят, что используйте Exception
только в исключительных обстоятельствах.
Итак, как вы справляетесь с нарушением правил бизнес-правил до ui элегантно?