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