You are allowed to have any method you want in your repository :) In both of the cases you mention, it makes sense to return the user with phone list populated. Normally user object would not be fully populated with all the sub information (say all addresses, phone numbers) and we may have different methods for getting the user object populated with different kind of information. This is referred to as lazy loading.

User GetUserDetailsWithPhones()
{
    // Populate User along with Phones
}

For updating, in this case, the user is being updated, not the phone number itself. Storage model may store the phones in different table and that way you may think that just the phones are being updated but that is not the case if you think from DDD perspective. As far as readability is concerned, while the line

UserRepository.Update(user)

alone doesn't convey what is being updated, the code above it would make it clear what is being updated. Also it would most likely be part of a front end method call that may signifiy what is being updated.

For the lookup tables, and actually even otherwise, it is useful to have GenericRepository and use that. The custom repository can inherit from the GenericRepository.

public class UserRepository : GenericRepository<User>
{
    IEnumerable<User> GetUserByCustomCriteria()
    {
    }

    User GetUserDetailsWithPhones()
    {
        // Populate User along with Phones
    }

    User GetUserDetailsWithAllSubInfo()
    {
        // Populate User along with all sub information e.g. phones, addresses etc.
    }
}

Search for Generic Repository Entity Framework and you would fine many nice implementation. Use one of those or write your own.


Your example on the Aggregate Root repository is perfectly fine i.e any entity that cannot reasonably exist without dependency on another shouldn't have its own repository (in your case Phone). Without this consideration you can quickly find yourself with an explosion of Repositories in a 1-1 mapping to db tables.

You should look at using the Unit of Work pattern for data changes rather than the repositories themselves as I think they're causing you some confusion around intent when it comes to persisting changes back to the db. In an EF solution the Unit of Work is essentially an interface wrapper around your EF Context.

With regards to your repository for lookup data we simply create a ReferenceDataRepository that becomes responsible for data that doesn't specifically belong to a domain entity (Countries, Colours etc).


If phone makes no sense w/o user, it's an entity (if You care about it's identity) or value object and should always be modified through user and retrieved/updated together.

Think about aggregate roots as context definers - they draw local contexts but are in global context (Your application) themselves.

If You follow domain driven design, repositories are supposed to be 1:1 per aggregate roots.
No excuses.

I bet these are problems You are facing:

  • technical difficulties - object relation impedance mismatch. You are struggling with persisting whole object graphs with ease and entity framework kind a fails to help.
  • domain model is data centric (as opposed to behavior centric). because of that - You lose knowledge about object hierarchy (previously mentioned contexts) and magically everything becomes an aggregate root.

I'm not sure how to fix first problem, but I've noticed that fixing second one fixes first good enough. To understand what I mean with behavior centric, give this paper a try.

P.s. Reducing repository to aggregate root makes no sense.
P.p.s. Avoid "CodeRepositories". That leads to data centric -> procedural code.
P.p.p.s Avoid unit of work pattern. Aggregate roots should define transaction boundaries.


This is an old question, but thought worth posting a simple solution.

  1. EF Context is already giving you both Unit of Work (tracks changes) and Repositories (in-memory reference to stuff from DB). Further abstraction is not mandatory.
  2. Remove the DBSet from your context class, as Phone is not an aggregate root.
  3. Use the 'Phones' navigation property on User instead.

static void updateNumber(int userId, string oldNumber, string newNumber)

static void updateNumber(int userId, string oldNumber, string newNumber)
    {
        using (MyContext uow = new MyContext()) // Unit of Work
        {
            DbSet<User> repo = uow.Users; // Repository
            User user = repo.Find(userId); 
            Phone oldPhone = user.Phones.Where(x => x.Number.Trim() == oldNumber).SingleOrDefault();
            oldPhone.Number = newNumber;
            uow.SaveChanges();
        }

    }