However, the domain objects/entities need to be able to reference the repository.
Do they? Or do they need to reference the interface of the repository? Then the repository itself is just an implementation of that interface, a low-level detail not needed by the domain logic code.
The way I normally structure a repository pattern in my projects is:
- Domain Core Project (business models, core business logic, interfaces for dependencies)
- Dependency Projects (references Domain Core Project, implements interfaces)
- Application Projects (references Domain Core Project, references Dependency Projects either directly, or through configuration, or through an intermediary project which handles dependency injection)
As an example, suppose I'm using a Service Locator for my dependency injection (which I very often do). Then the business models only need to reference the Service Locator object (which itself is supplied by a factory and can be injected). So internal to a business model I might have something like this:
public class SomeBusinessModel
{
private ISomeDependency SomeProperty
{
get
{
return DIFactory.Current.Resolve<ISomeDependency>();
}
}
}
The DIFactory
has a static property called Current
which is basically a factory method returning a dependency injection resolver, and its interface has a method called Resolve
which takes a type and returns an instance.
So in this case...
SomeBusinessModel
is in the Domain Core Project
ISomeDependency
is in the Domain Core Project
IDIContainer
(the return type for Current
) is in the Domain Core Project
DIFactory
is in the Domain Core Project, and is initialized (it has an Initialize
method that sets the current injection container) by the Application Project for a specific dependency injection container
SomeDependency
(the actual instance type being returned by the resolver) is in a Dependency Project
In this setup, the business models know that there needs to be a repository, and require that one be supplied, but they don't have a hard dependency on them. The application supplies the actual implementations for those repositories, either directly by providing an instance or indirectly by configuring a dependency injection container to provide an instance.
All actual dependencies point inward from the implementation details (applications and dependencies) to the core business logic. Never outward.