放置验证逻辑的位置?在服务或存储库?

时间:2009-11-08 08:42:43

标签: c# design-patterns service repository

我有这样的逻辑,在将库存保存到数据库之前,我将检查库存中是否有相同的库存代码。我的问题是我应该在服务层或存储库层中放置逻辑。这是示例代码:
选项1:放入服务层,我将IsAccountAlreadyExists方法放在服务层中

public override void Save(AccountInfo accountInfo)
{
    using (var scope = new TransactionScope())
    {
        if(this.IsAccountAlreadyExists(accountInfo))
        {
            throw new AccountAlreadyExistedException(
                "Account Code : " + accountInfo.AccountCode +
                " already existed.");
        }

        accountRepository.Save(accountInfo);
            scope.Complete();
    }
}

选项2:我将把IsAccountAlreadyExists逻辑移动到存储库层。

public override void Save(AccountInfo accountInfo)
{
    try
    {
        using (var scope = new TransactionScope())
        {
            accountRepository.Save(accountInfo);
            scope.Complete();
        }
    }
    catch(AccountAlreadyExistedException e)
    {
        ...
    }
}
你有什么看法?

5 个答案:

答案 0 :(得分:6)

我认为这是三层(定义了连接每个部分的接口):

  • 数据存储库 - 仅用于存储和检索原始数据。尽可能少的逻辑在这里。
  • 商业模式 - 所有智慧都在这里,包括验证。
  • 服务(即客户端访问) - 一个非常薄的部分,足以提供与客户端的连接。

这样,如果您选择以其他方式存储数据,验证逻辑不会随之丢失。

同样,如果您决定提供不同形式的客户端访问,则无需复制大量逻辑即可实现。

答案 1 :(得分:5)

服务 - 存储库模式可能有点主观。当然有不好的/完全错误的例子(虽然这个不是),但通常情况下,这取决于个人偏好。

我倾向于遵循的模式是存储库层应该99%专门用于数据源的读写 - 删除操作。我的存储库层执行的唯一验证是模型上的非常低级别的验证:这通常通过Model.IsValid方法完成。它仅检查所需字段以及这些字段的格式/基本内容(例如,应该保留和发送电子邮件的字段的注册检查)。存储库层不会尝试理解这些错误 - 如果模型无效,那么它会抛出异常,并结束它的处理。

应在服务层执行业务逻辑检查。如果允许将User对象“分配”到特定模型(“Joe拥有记录X”),则服务层应执行检查以确保允许Joe拥有该记录等。要完成,我的服务层通常是还会检查模型上的IsValid方法,以预先防止数据层异常。

我对您的示例代码的唯一评论是方法名称“保存” - 这太模糊了。我更喜欢创建/插入和更新 - 很明显,前者将导致创建一个新记录(偶尔我用一个新值覆盖对象的Id字段),而后者应该更新记录,如果没有传递Id值,则抛出异常。

答案 2 :(得分:2)

既然你提出了意见,那么就是这样。 :-) 将验证逻辑放在最接近数据的最低层。所以在这种情况下,逻辑应该在Repository中。如果愿意,服务可以捕获异常并翻译它。但是“帐户应该是唯一的”标准是存储库,IMO的一个特征。

答案 3 :(得分:1)

我把它放在服务层。存储库处理持久性逻辑。

服务于其他对象以完成工作是服务职责。

答案 4 :(得分:0)

我更喜欢将检查放在最接近数据的地方 - 所以在这种情况下,这将是数据库。

我会根据你所做的条件制定一个独特的约束,以确保帐户不存在。这将确保没有人可以绕过我的中间层并插入错误的数据。

然后我可以将检查放在存储库层中作为额外的预防措施。