Thursday, September 1, 2011

Entity Framework Validation Bug (DBEntityValidationException)

The Problem

You can download the source code for this project from http://tinyurl.com/3ep48o5. The project is just a simple unit test project that shows the bug and workaround options.  You need VS2010 and a SQLEXPRESS or SQLSERVER instance to run the sample.  If you are using the full blown SQLSERVER, then you will need to uncomment the connection string from the app.config file.  The database will automatically be generated when you run the tests.
I have had the opportunity to play around with the EF 4.1 code first constructs that exist. I am really enjoying the development experience, albeit my use case is relatively simple at the moment.  Anyhow, one of the features I really like is the ability to place navigation properties in model objects without the associated foreign key id in the code.  The BadParentEntity model shows an example of this (see below).
public class BadParentEntity { public int Id { get; set; } public string Description { get; set; } #region navigation properties [Required] public virtual ChildEntity Child1 { get; set; } [Required] public virtual ChildEntity Child2 { get; set; } #endregion }

Notice there are two ChildEntity navigation properties while there are no foreign key properties to these child entities. The EF code first conventions infer that a column Child1_Id and Child2_Id must exist on the BadParentEntity table and they must refer to the Id column on the ChildEntity table. I think this is great, it allows me to remove the id based relationships and infer them based on the complex model mappings between types. Unfortunately, I recently ran into an issue that required me to place the foreign key relationships back in. I wanted to share the solution I came up with for it. The test method below, exhibits the problem. This test ends up throwing a DbEntityValidationException with two validation error messages of (“The Child1 field is required”, and “The Child2 field is required”)… weird… they are there in the database.

[TestMethod] [ExpectedException(typeof(DbEntityValidationException))]public void ExhibitBugTest() { using (var repos = new TestBugRepository()) { var parent = repos.BadParentEntities.Where((x) => x.Id == 1).Single(); parent.Description = "THIS WILL FAIL!"; try { repos.SaveChanges(); } // EXCEPTION!!!! WHAT catch (DbEntityValidationException dbEx) { foreach (var validationErrors in dbEx.EntityValidationErrors) { foreach (var validationError in validationErrors.ValidationErrors) { Debug.WriteLine(validationError.ErrorMessage); } } // rethrow, we want to fail this test if this happens throw; } } }

The parent I selected from the repository exists via some pre-seeded data in the database, and the this parent has a child defined in both collections. I would expect this code to work because all I am doing is updating a description column. It seems as though the EF thinks that the Child foreign keys are not present because they were never de-referenced and they are lazy. I have come up with a handful of ways to work around it, but most of them leaked ORM details out into the code (and I don’t like that). So below are the workaround I came up with and the final one I settled on.

Workarounds
The first option I came up with is to turn off entity validation when saving changes through the repository. I don’t recommend this option because the advantages of model verification automatically happening are highly beneficial and some of the other workaround options are a little less drastic. In order to do this you can do the following. With the below code I no longer receive an exception when saving my entity modifications.


DON’T DO THIS

[TestMethod]public void WorkaroundValidateOnSaveDisabled() { // open a new connection and get the parent. update a single column and save using (var repos = new TestBugRepository()) { repos.Configuration.ValidateOnSaveEnabled = false; var parent = repos.BadParentEntities.Where((x) => x.Id == 1).Single(); parent.Description = "Updated!"; repos.SaveChanges(); } }


The next option has to do with forcing the lazy evaluation of the child properties. Again, I don’t recommend this solution because it leaks usage requirements too much onto the user’s of the model objects, the code for that looks like… as you can see a reference to each child is saved off in a locally scoped variable.

DON’T DO THIS

[TestMethod]public void WorkaroundOption1() { using (var repos = new TestBugRepository()) { var parent = repos.BadParentEntities.Where((x) => x.Id == 1).Single(); parent.Description = "Updated From Workaround!"; // just dereference the children to workaround var child1 = parent.Child1; var child2 = parent.Child2; // NO EXCEPTION repos.SaveChanges(); } }

The last option involve updating the model to be defined in a manner that the entity framework no longer throws an error. The options here it to just remove the [Required] attribute from the navigation properties altogether. EF will no longer verify their presence, but those attributes were probably there for a reason and we don’t want to lose that data integrity.  Unfortunately I chose this option.

Unofortunately, do this

public class NotRequiredWorkaroundParent { public int Id { get; set; } public string Description { get; set; } public virtual ChildEntity Child1 { get; set; } public virtual ChildEntity Child2 { get; set; } }