I'm personally not in a group of people who think that Entities
should not access Repositories
. So to me, the answer to your question is "Yes, sure, go ahead."
But in case you don't want to do that, I would like to change Ewan's solution slightly.
// notice this is not general vehicle repository
public interface IVehicleReservationRepository
{
bool IsReserveAvailable();
}
public class Vehicle
{
// notice Reserve being private
// should only be called when reservation can happen
private void Reserve()
{
// do stuff ...
}
public class ReservationService
{
private IVehicleReservationRepository _vehicleReservationRepo;
public ReservationService(IVehicleReservationRepository vehicleReservationRepo)
{
_vehicleReservationRepo = vehicleReservationRepo;
}
public void Reserve(Vehicle v)
{
bool isReserveAvailable = _vehicleReservationRepo.IsReserveAvailable();
if (isReserveAvailable)
{
v.Reserve();
}
}
public void ReserveAll(IEnumerable<Vehicle> vehicles)
{
// efficient reservation for multiple vehicles
// doesn't need to call repository for every vehicle
}
}
}
By making the RegistrationService
nested of Vehicle
, it allows it to access it's private members. This is because making the service nested to the entity couples them together. So the service is integral part of the entity. It is still possible to use DI to create the ReservationService
and having it separate like this makes it clear what operations make use of the repository service.
Another thing to point out is that instead of using generic IVehicleRepository
, I created special IVehicleReservationRepository
, that is only used in this use case. In the end, it might be implemented on VehicleRepository
, but that is unrelated to this problem. Making interface specific for one use case is good usage of interface segregation principle and would make testing easier, as you don't need to worry about other methods present on full repository.
Last thing that came to my mind is scenario, where you might want to reserve multiple vehicles. If you had Reserve method on a Entity, you would have to call it on each vehicle, calling repository, and thus database, for every entity. But having separate service allows you to optimize this by calling repository once for multiple vehicles. As seen in ReserveAll
method on the ReservationService
.