Am I misinterpreting the intent of the Repository pattern?
I'm going to say "yeah", but know that me and every person I've worked with has asked the same thing for the same reason... "You're not thinking 4th dimensionally, Marty".
Let's simplify it a little and stick with constructors instead of Create methods first:
Editor e = new Editor("Editor Name");
e = editorRepository.Add(e);
Project p = new Project("Project Name", e);
p = projectRepository.Add(p);
Underneath, your project repository is always storing a valid owner (p.EditorId
) into the project data as it's created, and however you re-populate an editor's projects, it will be there. This is why it's a good practice to put all required properties into constructors. If you don't want to pass the whole object, just the e.Id
will do.
And if I want to lazy load the member Editors, the Project needs a reference to the repository as well?
Now, as to how to re-populate an editor's projects on demand, you have a couple of choices depending on what you're going for. Straight Repository says you want:
IEnumerable<Project> list = projectRepository.GetAllProjects()
.Where(x => x.editorId == e.Id);
But where to put it? Not inside Project, or Editor, you're right, or they will have to get access to repositories and that's no good. The above snippet is loosely coupled, but isn't reusable on its own. You've just reached the limits of Repository Pattern.
Next up is an Adapter Layer for your application, with a shared source of repositories (StaticServiceWrapper
) and either some sort of EditorAdapter object (or Aggregate or whatever you'd call them) or now you can mix in extension methods that can talk to any and all necessary repositories fluently. I haven't done it exactly this way in a production system, but to show you a concise example:
public static class Aggregators
{
// one to one, easy
public static Editor GetOwner(this Project p)
{
return StaticServiceWrapper.editorRep.GetEditorById(p.editorId);
}
// one to many, medium
public static IEnumerable<Project> GetProjects(this Editor e)
{
return StaticServiceWrapper.projectRep.GetAllProjects()
.Where(x => x.editorId == e.Id);
}
// many to many, harder
public static IEnumerable<Editor> GetMembers(this Project p)
{
var list = StaticServiceWrapper.projectMemberMap.GetAllMemberMaps()
.Where(x => x.projectId == p.projectId);
foreach ( var item in list )
yield return StaticServiceWrapper.editorRep.GetEditorById(item.editorId);
}
}
Basically, once your GetAll,GetById,Add,Update,Remove Object Repository is done, you've got to leave the associations alone and move on up the object/layer hierarchy to the fun parts like Adapters and Caches and Business Logic ("Oh, my!").