我有一个ASP.Net应用程序,它有很多关于是否可以将对象提交到数据库的业务规则。
在基础层面上,一个人是sprint的一部分,sprint是项目的一部分。
基本规则是:
一个人被分配到sprint,但可能不是sprint的完整持续时间(具有开始和结束日期)。所以,当他们分配这个人时,他的开始日期和结束日期必须介于(包括)sprint的开始和结束日期之间。
项目可以有很多冲刺,但没有一个可以在项目开始/结束日期之外。
我的解决方案有一个UI项目,服务层,业务层和数据访问层。
我现在在验证中构建,但我不确定在我的应用程序的哪个级别,应该进行验证。我不相信它在UI上,因为那时我需要在我的ASP.Net项目上复制验证规则......也许我的WinForms前端...
我认为应该是商业逻辑,因为它有业务规则。所以,我打算创建一个名为“Validations”的类,并且对于存储到数据库的每个业务对象,我在我的Validations中有一个名为“IsObjectOK”的方法,接收我要验证的对象类型,并返回错误列表。
所以:
public List<String> IsObjectOK(SprintDto source)
{
// Do validations, and return list of errors, or NULL if none
}
验证规则的一个示例可能是:
var Project = BusinessLayer.GetProject(source.ProjectId);
// check if Start/End dates fall between Project.Start and Project.End dates
如果出现问题,请将其添加到错误列表中。
这似乎是一个很好的方法。我正在寻找关于我的处理验证方法的确认,以及任何提示和技巧?我不应该担心数据库命中吗?我的意思是,对于sprint,我需要验证大约6或7个'规则',所有这些规则都可以从不同的表中获取数据。因此,对于单个保存,这是7个数据库查询(加上连接开销)。 (SQL Server 2012)。我认为这并不是一件令人担心的事情,因为它全都是商业和数据层。
答案 0 :(得分:0)
我不担心数据库命中,直到你不得不这样做。有很多方法可以在之后优化,从而使您的架构正确。一个好的缓存层会使大部分内容消失,如果没有,你总是可以写一个单独的域对象,它是“SprintValidation”对象,包含验证它所需的所有数据。
在您知道这是一个问题之前,不要先破坏您的架构以获得性能。
答案 1 :(得分:0)
当一个物体有可能变得不一致时,我总是试图尽可能早地和尽可能地设置障碍来防止它。
<强>早期强>
理想情况下,处于非相干状态的对象甚至不应到达UI上方的层。日期间隔通常是您在创建或修改Sprint时可以在客户端轻松检查的内容。用户将欣赏关于出错或不可能的立即反馈(例如,灰色按钮),双重保险总是很好。但是,通过更复杂的验证可能不太可行。
<强>牢牢强>
在业务中,尝试将这些规则建模为强制执行一次的不变量,而不是验证,您可能需要多次执行。换句话说,请确保您的业务对象为always valid。
在创建时(在构造函数或工厂中)强制执行不变量,并尽可能使对象不可变Value Objects。你的例子中的PersonAssignment是一个很好的候选人。价值对象是你从不打扰修改的简单结构,你只用另一个替换它们,所以保持它们始终一致是一件小事。
对于您无法理智地完全不可变的对象(例如Sprint),您仍然可以过滤掉某些字段的不需要的修改。例如,将属性StartDate和EndDate的setter修改为不接受Project范围之外的日期。
有时,与状态变化相关的业务规则更复杂,涉及许多条件。我发现在单个方法中定义业务操作总是更好,并在那里包含所有不变检查,而不是让你的实体进入破坏状态,然后尝试验证它。
简而言之:缩小修改几个地方的机会,并毫不犹豫地在那里执行严格的执法,这样你就可以依靠信心而不是怀疑。