views:

94

answers:

5

I have some logic like this, before save the stock into the db, i will check whether there is stock has the same stock code in the database. My question is where should I put the logic, in the service layer or repository layer. here is the sample code:
option 1: put in the service layer, i put the IsAccountAlreadyExists Method in the service layer

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();
    }
}

option 2: I will move the IsAccountAlreadyExists logic to the repository layer.

public override void Save(AccountInfo accountInfo)
{
    try
    {
        using (var scope = new TransactionScope())
        {
            accountRepository.Save(accountInfo);
            scope.Complete();
        }
    }
    catch(AccountAlreadyExistedException e)
    {
        ...
    }
}

what's your opinion?

A: 

Since you asked for opinions, here it is. :-) Put the validation logic at the lowest layer closest to the data. So in this case, the logic should be in the Repository. The Service can catch the Exception and translate it, if it wants to. But the criteria that "Accounts should be unique" is a feature of the Repository, IMO.

binil
A: 

I'd put it in the service layer. The repository handles persistence logic.

It's the service responsibility to call out to other objects to get the job done.

BennyM
A: 

I prefer putting checks closest to the data - so in this case that would be the database.

I would make a unique constraint based on the conditions you are doing to ensure that the account does not exist. This would make sure that nobody can bypass my middle tier and insert bad data.

Then I can put the check in the repository layer as an additional precaution.

Raj More
+2  A: 

Service - Respository patterns can be a little subjective. Of course there are bad / completely wrong examples out there (this one isn't though), but more often than not, it's down to personal preference.

The pattern that I tend to follow is that the repository layer should be 99% dedicated to read-write-delete operations with your data source. The only validation that my repository layer performs is very low-level validation on the models: this is typically done via a Model.IsValid method. It checks only for required fields and the format/ basic content of those fields (e.g. a reg-ex check of a field that is supposed to hold and email). The repository layer does not attempt to make sense of these errors - if the model is not valid, then it throws an exception, and that ends it's handling.

Business Logic checks should be performed in the Service Layer. If User objects are allowed to be 'assigned' to a particular Model ("Joe owns record X"), the service layer should perform the checks to ensure that Joe is allowed to own that record etc. To be complete, my Service layer generally also checks the IsValid method on the model as well, in order to pre-empt data-layer exceptions.

My only comment with your example code is with the method name "Save" - this is too ambiguous. I prefer Create/Insert and Update - it is clear then that former will result in a new record being created (to the occasional extent that I overwrite the Id field of the object with a new value), whilst the latter should update a record, and thus would throw an exception if no Id value is passed.

iAn
+2  A: 

I consider this to be three tiers (with an interface defined to connect each piece):

  • Data Repository - only for storing and retrieving raw data. As little logic goes here as possible.
  • Business Model - all the smarts goes here, including validation.
  • Service (i.e. client access) - a very thin piece, just enough to provide a connection to the client.

This way, if you choose to store your data in some other fashion, the validation logic doesn't get lost with it.

Similarly, if you decide to provide a different form of client access, you do it without needing to replicate a bunch of logic.

Mike Hanson