3

I want to add a validation class to an Entity, so it can check it is valid before being entered into the database. (The check is for business requirements, not db constraints).

I have the class

public class MyEntity
{
     private readonly IValidatorFactory _validatorFactory;
     public MyEntity(IValidatorFactory validatorFactory)
     {
         _validatorFactory = validatorFactory;
     }

     //Entity Properties Removed For Clarity

     public void Validate()
     {
         if(_validatorFactory == null)
         {
                throw new ArgumentNullException("Validator Factory was null, cannot validate this item");
         }

         var validator = _validatorFactory.GetValidator(this.ItemTypeId);
         valid = validator.Validate();

     }
}

Using dependency injection, I am struggling to see how I can cleanly resolve the dependency when the project uses EF6. If I return a DbSet, it will of course not know about the requirement for the validator. A parameterless constructor is required.

Lotok
  • 4,517
  • 1
  • 34
  • 44
  • In general, it's usually a bad idea to use Dependency Injection on Entitties: http://stackoverflow.com/a/4836790/126014 – Mark Seemann Feb 23 '16 at 12:48
  • Where do you call Validate() on these entities? – Tamas Ionut Feb 23 '16 at 12:48
  • Validate would be used when data is imported to the system, for that the factory can be injected and I could have a parameterless constructor for selects. Problems might occur later if an entity is being changed and updated, it would be required to call validate() on the controller before allowing a final save. – Lotok Feb 23 '16 at 12:53
  • @MarkSeemann I am not sure I agree that injecting into an entity violates the Single Responsibility rule. Doing so actually allows for the validation to be handled by another class which is exactly what SR is all about. It also conforms to Open/Closed rule as using the interface allows for polymorphism / extending rather than editing. I could have had a service layer handle the validation, but then that move towards the anemic anti-pattern and procedural code – Lotok Feb 23 '16 at 12:56
  • @James why the Factory, the Validator and all these bells and whistles ? What do you gain from abstracting the concept of a Validator ? – guillaume31 Feb 23 '16 at 13:32
  • @guillaume31 It allows me to pass in different validation classes based on the flavour of entity. The entity in question has about 4 different types with identical properties but different business requirements and validation rules. It seemed like a perfect use of polymorphism to abstract the validator away so the client doesn't need to know which flavour it is dealing with – Lotok Feb 23 '16 at 13:35
  • 1
    Why not use a visitor or pipeline pattern? Then you don't need to make any changes to the entites. You just pass the entity you want to validate to the validator. – Matthew Whited Feb 23 '16 at 13:40
  • @James I would suggest reading some articles before making this decision. I would recommend this one: https://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/ – Red Feb 23 '16 at 13:43
  • @MatthewWhited That might be the way I need to go with it, based on the EF restriction. I wanted to avoid falling into the anemic domain model pattern and try to stick with OO principals but there are times when it makes more sense to accept there are always exceptions to the rule. -raderick I will have a wee read now – Lotok Feb 23 '16 at 13:46
  • Don't worry about "OO principals" that much... Pretty much everyone you ask will have their own opinions on what is right/true/valid. Everyone else will say those are all "anti-patterns". – Matthew Whited Feb 23 '16 at 14:38
  • BTW, you can have your repository Save/Upsert methods use your validator to ensure all saves are consistent. You don't need (and often don't want) to validate reads. – Matthew Whited Feb 23 '16 at 14:40

2 Answers2

4

Firstly, I don't think you should be trying to use DI with your entities. Validation should probably also occur within your entity itself rather than using an external validator (passed into the Validate method or created with a ValidatorFactory).

Entity Framework has multiple ways to do validation built in. Have you tried any of those?

The simplest form would be adding attributes to properties, such as Required and StringLength. For more complex validation you could have your entities implement IValidateObject or override DbContext.ValidateEntity.

Using any of those methods a DbEntityValidationException will be raised when validation fails when you call DbContext.SaveChanges. You can also trigger validation without throwing exceptions by calling DbContext.GetValidationErrors.

kjbartel
  • 10,381
  • 7
  • 45
  • 66
2

The need for an external validator feels like a smell to me - not to mention the convoluted ValidatorFactory.

If you want to avoid the anemic domain antipattern as you rightly said, you might as well include validation in the entities themselves and keep them valid at all times.

Another thing that doesn't make sense to me is that you identified 4 entities with "different business requirements and validation rules". IMO this is precisely where you need the specificity of ad hoc entities each enforcing its own rules internally, as opposed to the genericity of an external Validator abstraction.

Regarding the similar part of your 4 entities, i.e. the data, I would try to extract it to meaningful Value Objects and compose your entities of these objects.

guillaume31
  • 13,738
  • 1
  • 32
  • 51