C# – Repository pattern and/or/vs business logic layer

cdesign-patterns

I have a problem I want to know your opinion.

I am trying to use Repository Pattern. I have a repository object which load data to a POCO. I have also created a Business logic layer which adds a little bit of functionality but basically wraps the POCO. So in the end I have a BLL which loads DAO with usage of repository.

I am not very happy with this solution. I have a three layers but I feel that BLL is not providing enought functionality to keep it there. On the other hand I do not want to put my logic in the repository layer nor data access layer?

So my question is where should I put logic for application? Which solution do you use(DAO + repo or DAO + BLL + rep or any other)?

Best Answer

There are two basic ways to think about business rules when designing your domain.

1.) The domain entities are basic POCO/DTOs. And you hand them off to domain services. These services could be as simple as another class, or they really could be actual services sitting on another server.

var user = repository.Find(x => x.UserName == userName);
if (userLogonService.IsValidUser(user, password)) {
   userLogonService.UpdateUserAsLoggedOn(user);
}
repository.SaveChanges();

2.) The domain entities contain their own operation logic. This is closer to what many MVC patterns will follow. And since you asked, this is the model that I prefer.

var user = repository.Find(x => x.UserName == userName);
if (user.CheckPassword(password)) {
    user.LogOnNow();
}
repository.SaveChanges();

Both are completely valid patterns. #1 has a discrete business operation tier, but suffers from an Anemic Domain Model. #2 can lead to big domain entities if you domain starts to become complicated, or if a model can do a lot of things.

EDIT #1: Response to John Kraft

Oven.Bake(myPizza) vs. myPizza.Bake()

I mostly agree. Do you have a single Oven service, or do you have dozens of available ovens stored in an oven repository where oven is just another domain entity? In #2, the oven is part of the domain. The way I tend to do domain modeling, most nouns are domain entities, unless you are 100% sure that there is exactly one of the thing.

But something does happen to pizza when it is baked.

interface ICanBeBaked {
    int BakeMinutes { get; }
    int BakeTemp { get; }
    void Bake();
}
class Pizza : ICanBeBaked {
    int BakeMinutes { get { return 15; } }
    int BakeTemp { get { return 425; } }
    void Bake() {
        // melt cheese!
        this.isBaked = true;
    }
}
class Oven {
    void Bake(ICanBeBaked thingToBake) {
        // set the temp, reserve this oven for the duration, etc.
        thingToBake.Bake();
    }
}