Entity Framework Code First Validation
You can turn off validation completely (for instance, if an entity has already been validated).
//default to validate on save
context.Configuration.ValidateOnSaveEnabled = false;
Validation Rules
Use DataAnnotations:
[Required, StringLength(50)]
public string LastName { get; set; }
Or fluent mapping:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Entity<Person>()
.Property(p => p.LastName).HasMaxLength(50).IsRequired();
Or IValidatableObject (or IDataErrorInfo).
public class Customer : IValidatableObject
{
public int Id { get; set; }
public string FirstName { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if (FirstName.Contains("\n"))
{
results.Add(
new ValidationResult("Newline character is illegal",
new[] { "FirstName" }));
}
return results;
}
}
Valildate In DbContext
The context has two extension points into validation. ValidateEntity allows custom validation to be added:
protected override DbEntityValidationResult ValidateEntity(
DbEntityEntry entityEntry,
IDictionary<object, object> items)
{
//do the base DataAnnotations/fluent validation mapping
var result = base.ValidateEntity(entityEntry, items);
//do additional validation for customer
var customer = entityEntry.Entity as Customer;
//could be added or updated (change ShouldValidateEntity to include deleted)
if (entityEntry.State == EntityState.Added &&
customer != null)
{
if (customer.FirstName.Contains("\t"))
{
result.ValidationErrors.Add(
new DbValidationError("LastName", "Illegal character"));
}
}
return result;
}
ShouldValidateEntity is a simple boolean to add/exclude entities for validation.
protected override bool ShouldValidateEntity(
DbEntityEntry entityEntry)
{
if (entityEntry.Entity is Employee)
return false; //don't validate employees
if (entityEntry.Entity is Customer && entityEntry.State == EntityState.Deleted)
return true; //validate deleted customers
//default: validate all added and updated entities
return base.ShouldValidateEntity(entityEntry);
}
Validate OnSave vs On Demand
You can turn on and off validation on save.
//default to validate on save
context.Configuration.ValidateOnSaveEnabled = false;
For OnSave (default) you'll get a DbEntityValidationException:
using (var context = new DomainContext())
{
try
{
var newEmployee = new Employee { LastName = "Smith" };
context.Employees.Add(newEmployee);
context.SaveChanges();
}
//need a reference to System.Data (System.Data.Entity.Validation)
catch (DbEntityValidationException entityValidationException)
{
foreach (var result in entityValidationException.EntityValidationErrors)
{
//the entity
Console.WriteLine(result.Entry.Entity.ToString());
foreach (var error in result.ValidationErrors)
{
Console.WriteLine(error.PropertyName + " " + error.ErrorMessage);
}
}
throw;
}
}
For OnDemand, you can do for all tracked entities (context), a specific entity or a specific property.
//validate all context
var allResults = context.GetValidationErrors();
//validate entity
var result = context.Entry(newEmployee).GetValidationResult();
//validate property
var errors = context.Entry(newEmployee).Property(x => x.LastName)
.GetValidationErrors();