use*_*415 7 c# service design-patterns 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)
    {
        ...
    }
}
你怎么看?
我认为这是三层(定义了连接每个部分的接口):
这样,如果您选择以其他方式存储数据,验证逻辑不会随之丢失.
同样,如果您决定提供不同形式的客户端访问,则无需复制大量逻辑即可完成.
服务 - 存储库模式可能有点主观.当然,那里有不好/完全错误的例子(虽然这不是),但往往是个人偏好.
我倾向于遵循的模式是存储库层应该99%专门用于数据源的读写 - 删除操作.我的存储库层执行的唯一验证是模型上的非常低级别的验证:这通常通过Model.IsValid方法完成.它仅检查所需字段以及这些字段的格式/基本内容(例如,对应该保留和发送电子邮件的字段进行注册检查).存储库层不会尝试理解这些错误 - 如果模型无效,那么它会抛出异常,并结束它的处理.
应在服务层中执行业务逻辑检查.如果允许将User对象"分配"到特定模型("Joe拥有记录X"),则服务层应执行检查以确保允许Joe拥有该记录等.要完成,我的服务层通常还会检查模型上的IsValid方法,以抢占数据层异常.
我对你的示例代码的唯一评论是使用方法名称"保存" - 这太模糊了.我更喜欢创建/插入和更新 - 很明显,前者将导致创建一个新记录(偶尔我用一个新值覆盖对象的Id字段),而后者应该更新记录,因此,如果没有传递Id值,则会抛出异常.
既然你征求意见了,就写到这里了。:-) 将验证逻辑放在最靠近数据的最低层。所以在这种情况下,逻辑应该在存储库中。如果需要,服务可以捕获异常并对其进行翻译。但“帐户应该是唯一的”标准是存储库的一个特征,IMO。