Charlie Bear
Charlie Bear

Reputation: 2452

How much logic should i put my repository methods when using repository pattern?

i'm struggling a bit with repositories. I'm using C# and NHibernate. The question i have is : how much should my repository do before it calls a save or a get?

For example i have a user class which is an aggregate root. I want to call a method called "register" which will add the user and set some default values based on business rules and create some other entities which are also sub parts of the "user" root (ie address, groups, etc) . Should i call

userRepo.Register(newUser); 

which would be(ignoring the obvious issues):

Regsiter(User newUser){
 newUser.SomeProp  = "Default Data";
 Group g= new Group;
 g.SomeProp2 = "Default Data";
 newUser.Groups.Add(g);
 Session.Save(g);
 Session.Save(newUser);
}

or should i have put register in a business layer and have it do:

Regsiter(User newUser){
 newUser.SomeProp  = "Default Data";
 Group g= new Group;
 g.SomeProp2 = "Default Data";
 newUser.Groups.Add(g);
 userRepo.Register(newUser, g);// this does session.save on both objects.
}

Both seems slightly wrong.

What's the correct approach?

edit -------------------------------

thanks for all the responses. I can't decide who is the most right and therefore which answer to accept.

Generally everyone is saying put the business rules in another layer. that makes sense but i'm unsure about the data calls for groups - since groups aren't an aggregate root they shouldn't have their own repository so how do i go about adding and saving them? In my project adding a group to the user's group collection doesn't automatically create the group in the db; i also need to call session.save on the object. so do i put that into the user repo as userRepo.SaveGroup(g)?

If i have a createGroup() in the other layer then it'll either need to use it's own repo or the users. or am i being thick?

Upvotes: 10

Views: 3873

Answers (5)

Kevin Swiber
Kevin Swiber

Reputation: 1556

Determine where you want your Register method, maybe in a UserServices class. You can delegate object creation to a UserFactory. In a CreateNewUser() method, set up your defaults for the user and the Groups collection. Then call UserRepository.Save(newUser) to persist the data.

// UserServices class
public void Register(User newUser)
{
  // add custom registration stuff.
  _userRepository.Save(newUser);
}

// Application code
User user = UserFactory.CreateNewUser();
_userServices.Register(user);

// UserFactory
public User CreateNewUser()
{
  // all new user, group creation
}

Upvotes: 2

jrista
jrista

Reputation: 32960

From your code example, I would call the Register method a service operation. As a service operation, it would belong on a service, or on a business component, rather than a repository. According to Evans (of DDD fame), a repository is a collection-like interface to entities stored in your database. The general idea is that you provide basic CRUD-like access to your entities through a repository to abstract the rest of your code away from lower-level data access details like an ORM tool.

For your example with Register...your service method would validate input, build the User object, and then call your repository to "Add" your new entity to the "repository" (which could be a database...but could also be something else...as far as your domain is concerned, it doesn't matter...its just a repository.)

Upvotes: 1

John Fisher
John Fisher

Reputation: 22719

I see two potential "wrongness" issues (since you didn't really indicate what you thought was wrong with them).

  1. If the problem revolves around saving the group in the user registration method, or saving the user in the group methods, then you should separate these into different methods. (i.e. Register() would call RegisterGroup() or GetGroup()

  2. If the problem revolves around saving things before the user really is ready to conceptually save things, then keep track of what they wanted to add and wait until the overall "save" method is called before putting any of this information into storage.

Upvotes: 0

Kirschstein
Kirschstein

Reputation: 14868

What is your motivation for using the repository pattern in the first place? Usually, the repository is the abstraction of your object persistence logic. It retrieves items from (usually) a database and also handles updates, inserts and deletes.

If you were writing a test to check some logic and didn't want to hit the database what objects would you have to mock out? Usually the repository.

In scenario A) you cannot test a new user is created with the correct default data without directly hitting the database. Because of this, I would advocate keeping all business logic outside of the repositories and go with your second design

Upvotes: 3

Jarrett Meyer
Jarrett Meyer

Reputation: 19583

Personally, I keep the repository pattern as a substitute for sprocs. So my repository would have methods like getById(int id), save(), add(DomainObject obj) etc.

In a business tier, I'd have userManager.registerUser(string username, /* params, etc */). This would create the domain object. This method would just call the add() method in the data tier.

In short, the business tier is business-y, and the data tier is data-y.

Upvotes: 6

Related Questions