I have read this https://stackoverflow.com/questions/5818898/where-to-put-global-rules-validation-in-ddd and I have create my validator.
But now I need to create a validator that must check the order entity.
This is the problem: When I create or edit an entity "Car", I need to check 2 conditions:
I can't have the property Color with value "Red" if there are 10 or more entity Car with the Color = "Red". I can't have the property Color with value "Red" if the entity "Warehouse" haven't the entry with item code "FF0000" For this check i need to use my ICarRepository for count the item with property Red, and the IWarehouseRepostiory for check if there are an item with code "FF0000".
public class CarValidator : IValidator<Car>
{
public CarValidator(ICarRepository carRepository, IWahrehouseRepository wahrehouseRepository)
{
.....
}
private readonly IList<ISpecification<Car>> Rules =
new List<ISpecification<Car>>
{
new AvaiableRedColorSpecification(carRepository, wahrehouseRepository),
};
public bool IsValid(Car entity)
{
return BrokenRules(entity).Count() > 0;
}
public IEnumerable<string> BrokenRules(Car entity)
{
return Rules.Where(rule => !rule.IsSatisfiedBy(entity))
.Select(rule => GetMessageForBrokenRule(rule));
}
}
public class AvaiableRedColorSpecification : ISpecification<Car>
{
public bool IsSatisfiedBy(ICarRepository carRepository, IWahrehouseRepository wahrehouseRepository)
{
return carRepository.CountRedColor() < 10 &&
wahrehouseRepository.HaveItemCode("FF0000");
}
}
What is the best way to inject the my dependency, because in this way I need to inject the repository inside the Car entity for Add/Edit, I think it's not a good idea inject the repository inside my entity
[EDIT IMPLEMENTATION AFTER READ AL RESPONSE]
I have decide to use Validation Pattern, so I have create a
interface IRuleSpecification<T>
{
Task<ValidatorResult> IsSatisfiedAsync(T subject);
}
interface IValidator<T, TResult>
{
Task ExecuteCheckAsync(T entity, TResult validateObject);
bool IsValid { get; }
IEnumerable<ValidatorResult> BrokenRules { get; }
TResult ValidateObject { get; }
}
public static async Task<IValidator<CarDto, CarEntity>> FactoryCreator(CarDto dto, IEnumerable<IRuleSpecification<CarDto>> rules)
{ ... }
In this everytime I try to create entity car, I must pass the IRuleSpecification in the class that have a responsability to call factory (in my case use the CQRS I call CarCreatorCommand).
CarCreatorCommand recive the list of IRuleSpecification by dependy injection.
The implementation class of IRuleSpecification have injected the IRepository for receve the list of color avaiable. In this way the validator have the depence by IReposiory.
IsValid
too, since you return true if there are broken rules. If it breaks the rules, it ain't valid.