Entity Framework Combines Forces with AutoMapper to Unleash Evil StackOverflowException

Thor“Our ancestors called it magic but you call it science. I come from a land where they are one and the same.”

– Chris Hemsworth, Thor

To non-developers, computer programming must sometimes seem akin to magic.  Heck, even after years of being a .NET developer, I still marvel at the symphonies of code we create.  I love to see how the numerous NuGet/Bower packages of various versions weave together with our own code as glue to orchestrate amazing, impactful, applications.  At least when things work – and when they don’t those same components can be a nightmare!  Such was the case during a recent all-nighter that started with a StackOverflowException.

Spoiler alert – Entity Framework (EF) “Relationship Fixup” feature turned out to be the root of the problem.  I was experimenting with CodeGenHero’s data transfer object (DTO) template to have it include navigation properties – forward and reverse navigation properties.  It did such a good job generating code with parent objects pointing to child objects and child objects having references back to their parents.  Cool, I thought, now I can design API calls with the exact object graph of data I want in a single round trip.  Unfortunately, AutoMapper had other plans – moments after the Web API went to serialize the EF object returned by the repository classes into my DTOs, the server would throw a StackOverflowException.  What the heck?

Villain: Circular Dependency – as a simple example consider the following class:

namespace CircularDependency
{
  public class Person
  {
    public Person(string firstName, string lastName, Person parent)
    {
      FirstName = firstName;
      LastName = lastName;
      Children = new List<Person>();
      Parent = parent;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<Person> Children { get; set; }
    public Person Parent { get; set; }
  }

}

The example above depicts a ‘Person’ class with references to both a parent as well as a list of children.  Obviously, an instance of a parent person object may have multiple references to person objects that contain references back to the same parent, creating a circular dependency.  Other scenarios could involve different classes altogether.  For example, an ‘Order’ could reference a ‘Line Item’, which has a reference back to the order.  Unfortunately, this set-up will cause the wizardry of AutoMapper to conflict with the magic of Entity Framework.

The problem is that AutoMapper could not tell when to stop serializing the data.  This is not a new issue and there are stated solutions out there such as using the MaxDepth() and/or the PreserveReferences features.  However, for whatever reason, this approach was not working and, besides, I didn’t want to limit the depth.  What I wanted was the exact data I told EF to load and nothing more.  Server side, I had invested time in craftily assembling multiple bits of data into a single object graph that I wanted to send across the wire to my client in a single call (the traditional use for DTOs).

I started searching for a way to turn off or disable EF’s “relationship fixup” feature and found that it could not be disabled.  Call me stubborn or consider me persistent, either way I wasn’t going to let EF dictate my design!  So, I hunkered down and began “Operation Relationship Breakup” – my attempt to undo EF’s relationship fix-up feature (clever, I know).  The aim was to detect the first circular reference of each property and IEnumerable<T> and then null out its reference.  After several hours and multiple reflection algorithms, I had to throw in the towel.  Even when my algorithm came close to the desired behavior of nulling out EF’s circular references the performance impact was unacceptable.  I was adding overhead to undo something EF already burned cycles establishing.

I rationalized that many developers consider object designs with circular references to be bad practice, anyhow.  Thus, I set about removing the bi-directional reference properties in the DTO’s to only go one‑way in the object graph.  What this means, in the example below, is that the Person object might have a list of children and a primary key value for the parent, but it will not have a reference-based parent property.

Antihero: One-Way DTOs – no reference-based parent property:

namespace CircularDependency
{
  public class Person
  {
    public Person(string firstName, string lastName, int parentId)
    {
      FirstName = firstName;
      LastName = lastName;
      Children = new List<Person>();
      ParentId = parentId;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<Person> Children { get; set; }
    public int ParentId { get; set; }
  }
}

 

In the end, once the DTOs have one-way navigation then AutoMapper and Entity Framework play nice once again and I can go back to being productive.

Here’s a couple of relevant links:

https://stackoverflow.com/questions/37251043/automapper-throwing-stackoverflowexception-when-calling-projecttot-on-iquery

https://stackoverflow.com/questions/31107876/how-should-i-disable-entity-framework-table-refrenceforeign-list-from-each-obj