Первый , ваш первый вариант выше приемлемый . Тот факт, что другой dev может не заманить в ловушку для отказа, не является огромным недостатком. Это всегда имеет место с проверкой: вы ловите ее как можно раньше и элегантно, но главное - сохранить целостность ваших данных. Проще просто иметь ограничение в базе данных и ловить его, правда? Но да, вы хотите поймать это как можно раньше.
Если у вас есть область действия и время, лучше было бы иметь более умный объект, который бы справлялся с экономией , и, возможно, другие вещи, которые вам нужно обрабатывать последовательно. Есть много способов сделать это. Это может быть обертка для вашей сущности. (См. Шаблон декоратора , хотя я предпочитаю, чтобы у моего объекта всегда было свойство Data
для доступа к сущности). Для создания экземпляра может потребоваться соответствующая сущность. Ваш контроллер передаст объект этому смарт-объекту для сохранения (опять же, возможно, создание экземпляра этого смарт-объекта с помощью вашей сущности). Этот смарт-объект будет знать всю необходимую логику проверки и быть уверенным, что это произойдет.
Например, вы можете создать бизнес-объект JobRole. ("busJobRole", префикс шины для "business".) Может иметь коллекцию DataExceptions
. Контроллер принимает сущность JobRole, отправленную обратно, создает экземпляр busJobRole и вызывает метод SaveIfValid
, который возвращает true , если элемент был успешно сохранен, и false , если возникли проблемы с проверкой , Затем вы проверяете свойство busJobRoles DataExceptions
для точных проблем и заполняете свое состояние модели и т. Д. Может быть так:
// Check ModelState first for more basic errors, like email invalid format, etc., and react accordingly.
var jr = new busJobRole(modelJobRole);
if (jr.SaveIfValid == false) {
ModelState.AddModelError(jr.DataExceptions.First.GetKey(0), jr.DataExceptions.First.Get(0))
}
Мы так последовательно следуем этой модели, и я создал метод расширения для ModelState, чтобы принимать коллекцию NameValue (возвращаемую бизнес-объектами) (версия vb.net):
<Extension()> _
Public Sub AddModelErrorsFromNameValueCollection(
ByVal theModelState As ModelStateDictionary,
ByVal collectionOfIssues As NameValueCollection,
Optional ByRef prefix As String = "")
If String.IsNullOrEmpty(prefix) Then
prefix = ""
Else
prefix = prefix & "."
End If
For i = 0 To CollectionOfIssues.Count - 1
theModelState.AddModelError(prefix & CollectionOfIssues.GetKey(i),
CollectionOfIssues.Get(i))
Next
End Sub
это позволяет быстро и элегантно добавлять исключения (определяемые бизнес-объектами) в ModelState:
ModelState.AddModelErrorsFromNameValueCollection(NewApp.RuleExceptions, "TrainingRequest")
Ваше беспокойство о том, что другие разработчики могут не следовать установленному вами плану, очень обоснованно и хорошо продумано. Вот почему ваша схема должна быть последовательной . Например, в моем текущем проекте у меня есть две категории классов, которые действуют так, как я описал. Если они очень легкие и имеют дело только с кэшированием и проверкой, они являются классами «администратора данных» (например: BureauDataManager ). Некоторые из них являются объектами бизнес-предметной области, очень всеобъемлющими, которые я ставлю с префиксом «bus» (например, busTrainingRequest). Первые все наследуются от общего базового класса, чтобы обеспечить согласованность (и, конечно, уменьшить код). Согласованность допускает истинную инкапсуляцию, возможность обнаружения кода, для правильного кода, находящегося в правильном (единственном) месте.