[Entity Framework] DBContext API – Validation API (3) – SaveChanges

The “DbContext.GetValidationErrors()” method gives you the explicit control of when validating entities. But EF performs the validations autoutomatically when the “SaveChanges()” method is called.

 

1. SaveChanges

The  “SaveChanges()” method saves all changes made in the context to the underlying database.  It returns the number of objects written to the underlying database.

public class DbContext
{
  public int SaveChanges();
}

The “SaveChanges()” method is called, it does the following tasks:

  • Call the “GetValidationErrors()” for “Added” and “Modified” entities
  • If valid, call “ObjectContext.SaveChanges()” method

In turn, the  “ObjectContext.SaveChanges()” saves changes to the underlying data source.

  • Iterate all objects
  • Evaluate relationships and construct/excute SQL for each object

 

2. Detecting Errors

What happens when the validation fails during the “SaveChanges()” call? How can you detect it?

The “SaveChanges()” throws a “DbEntityValidationException“.

public class DbEntityValidationException : DataException
{
  public IEnumerable<DbEntityValidationResult> EntityValidationErrors { get; }
}

The exception has the “EntityValidationErrors” property. It is a collection of “DbEntityValidationResult” objects.

 

3. Data Annotations

Look at the following example.

public class MyCategory
{
  public int Id { get; set; }

  [MaxLength(5, ErrorMessage = "Category Name should be less than 5 characters.")]
  public string Name { get; set; }
}

public class MyProduct
{
  public int Id { get; set; }

  [Required(ErrorMessage="The product name is required")]
  public string Name { get; set; }
}

public class MyProductContext : DbContext
{
  public DbSet<MyCategory> Categories { get; set; }
  public DbSet<MyProduct> Products { get; set; }
}

public static class ValidationTest
{
  public static void DoValidation()
  {
    MyCategory c = new MyCategory { Id = 1, Name = "Toy" }; // Valid
    MyProduct p = new MyProduct { Id=1, Name = ""};

    using (MyProductContext context = new MyProductContext())
    {
      context.Categories.Add(c);
      context.Products.Add(p);

      c.Name = "Long Name"; // Invalid

      try
      {
        context.SaveChanges();
      }
      catch (DbEntityValidationException e)
      {
        foreach (DbEntityValidationResult result in e.EntityValidationErrors)
        {
          Console.WriteLine("{0} is Valid? {1}", result.Entry.Entity.ToString(), result.IsValid);

          foreach (DbValidationError err in result.ValidationErrors)
          {
            Console.WriteLine("{0}: {1}", err.PropertyName, err.ErrorMessage);
          }
        }
      }
    }
  }
}

The output is:

MyCategory is Valid ? False
Name: Category Name should be less than 5 characters.
MyProduct is Valid ? False
Name: The product name is required

 

4. Disabling Validation Before Save

To disable the validation during the “SaveChanges()” call, you can use the “DbContext.Configuration” property.

public class DbContext
{
  public DbContextConfiguration Configuration { get; }
}

public class DbContextConfiguration
{
  public bool ValidateOnSaveEnabled { get; set; }
}

Once you have the “DbContextConfiguration” object, you can set the “ValidateOnSaveEnabled” property to false.

using (MyProductContext context = new MyProductContext())
{
  context.Configuration.ValidateOnSaveEnabled = false;
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s