首先,您上面的第一个选项可以接受。另一个开发者可能不会陷入失败的事实并不是一个巨大的缺点。验证总是如此:您尽可能早且优雅地捕捉到它,但最重要的是保持数据的完整性。更简单的是,在数据库中设置一个约束并为此设置陷阱,对吧?但是,是的,您想尽早抓住它。
如果您有足够的范围和时间,最好有一个可以处理保存的更智能的对象,也许您需要始终如一地处理其他事情。有很多方法可以做到这一点。它可能是您实体的包装器。 (请参阅Decorator pattern,尽管我更喜欢让我的对象始终具有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)。有些是真正的业务领域对象,非常全面,我用“总线”作为前缀(例如:busTrainingRequest)。前者都继承自一个通用的基类,以确保一致性(当然也减少了代码)。 一致性允许真正的封装、代码的可发现性、正确的代码位于正确的(单个)位置。