November 2019

Volume 34 Number 11

[Data Points]

Backing Field and Owned Entity Changes in EF Core 3.0

By Julie Lerman

Julie LermanWell, this is it—the final issue of MSDN Magazine, and the final iteration of my column. I’ve decided to write about two of my favorite topics, Entity Framework Core (EF Core) and Domain-Driven Design (DDD). I’ve explored using Entity Framework (EF) and EF Core as a mapper between DDD-influenced domain models and relational databases a number of times over the years. Now EF Core 3.0 has just been released (in September 2019), so I’ll wrap up with a look at some of the improvements that help with these mappings.

My most recent exploration was expressed in a three-part series about EF Core 2.0 as a mapper between DDD models and relational databases. I’ll focus in these last pages on changes brought with EF Core 3.0 that improve the experiences of encapsulating logic with backing fields and of mapping value objects.

Backing Basics in EF Core

EF Core introduced support for backing fields, and each iteration brought a better experience with increased support. While backing fields aren’t specific to DDD, they do allow you to encapsulate properties of your classes, and that’s very important for DDD. The encapsulation lets you more easily control interaction with your classes and APIs to ensure they aren’t intentionally or accidentally misused.

EF6 only maps to properties, not to fields, though it does allow you to protect the value of a property by using a private setter. Because EF uses reflection to materialize query results, it is able to set the value of the property. But the property itself needed to be public:

public string Name {get; private set;}

That covered a lot of cases, but not if you really wanted the property to be private. A common use case might be the key property. EF needs to interact with it, but you may not want developers to read it directly or even use it in queries.

EF Core’s backing field support can map to backing fields whether you explicitly define backing fields or rely on inferred backing fields to comprehend properties. This allows EF Core to recognize even private properties when creating migrations, as well as to populate them when materializing query results. In this case I'm not even bothering with a getter and setter, but just using an expression body to return _companyId:

private int _companyId;
private int CompanyId =>_companyId;

If the property is private, but you don’t declare a backing field, EF Core will infer it for you when building the data model. In the specific case of making the key private, the ModelBuilder won’t be able to see the private property, so you’ll need to tell EF Core that it’s the key:

modelBuilder.Entity<Company>().HasKey("CompanyId");

EF Core is able to see that there’s a backing field (_companyId) related to the property so it can materialize results to that field, which will then feed the property. If the backing field doesn’t align with the property by convention, you can pair them up with a configuration in the DbContext.

Up through 2.2, EF Core would default to reading and writing property values through an available getter and setter even if there was a backing field available, with one exception—when materializing objects from queries. This exception ensured that any special business logic in a setter would not be triggered just because you were retrieving data from the database.

For example, if you edit the EmployeeCount of the company class, the business rule has a message fired off about the change:

private int _employeeCount;
   public int EmployeeCount
   {
     get { return _employeeCount; }
     private set
     {
       _employeeCount = value;
       SendEmployeeCountChangedMessage();
     }
   }

That doesn’t make sense if you’re just retrieving the company data from the database. So, because there’s a backing field available, EF Core would set the value using the _employeeCount field.

Backing Field Changes in EF Core 3.0

The team wanted to make sure that as a mapper, EF Core 3.0 aligns better with how we think about object persistence rather than just tying everything to public properties. From Microsoft Program Manager Diego Vega:

“EF Core’s goal should be to facilitate persisting and rehydrating objects from the database, and that is better achieved by mapping the object’s state, which is all represented by the object’s fields (even for automatic properties, there is always a backing field). On the other hand, the decision to add a public property on an object has more to do with the intent to expose specific data from the object to the rest of the program, and should not be determined by persistence concerns.” This truly brings us back to our DDD-focused design.

Vega continues, “There are always going to be cases in which you need to exclude some field (or property) from the mapping, because the state in the field represents some calculated value that is cached in memory but doesn’t need to be persisted, but mapping to backing fields provides a superior default starting point than mapping to public properties.”

So the biggest change to backing fields in EF Core 3.0 is that EF will always map to backing fields in all cases rather than only when querying.

Even with the exception of queries, there had been a case reported where the query wasn’t using the backing field—when the backing field was a navigation property. Here’s an example where an employee class has a navigation property to the employee’s company. If I edit the employee’s company using the navigation property, that should trigger some other behavior, in this case sending a message, like so:

private Company _company;
public Company Company
{
  get { return _company; }
  set
  {
    _company = value;
    SendEmployeeChangedCompany();
  }
}

Again, it doesn’t make sense for that to happen if I’m just populating the Company property using a query such as:

context.Employees.Include(e=>e.Company).FirstOrDefault();

With EF Core 3.0, rather than specifying this additional case for querying, the broader decision (explained earlier) was made to always read or write to a backing field if it exists.

That’s the new default. However, remember (or note if this is new to you) that you can fine-tune how a DbContext uses backing fields for properties in the ModelBuilder. Its UserPropertyAccessMode setting can be set to one of six enums: Field (the default), FieldDuringConstruction, PreferField, PreferFieldDuringConstruction, PreferProperty and Property.

Because this is a breaking change, you can set the value back to the old default (PreferFieldDuringConstruction) or use your tests to see where the behavior is changing in order to align your code.

The other two changes to backing fields cover narrow cases. The first issue occurred because the naming convention for matching fields with properties only checked the name and had an order of precedence:

  1. _<camel-cased property name>
  2. _<property name>
  3. m_<camel-cased property name>
  4. m_<property name>

It was possible to match a field to the wrong property—possibly even a property of the wrong type—if more than one field fit the pattern. Here’s an exaggerated example:

private string _name;
public string Name => _name;
private string m_name;
public string OwnerName => m_name;

Hopefully, your DDD practices and use of a ubiquitous language will ensure you never find yourself in this situation. However, in EF Core 3.0, if more than one backing field matches a property, it will throw a runtime exception, rather than quietly making what could be the wrong choice.

The real problem with the preceding code is that OwnerName and m_name don’t fit any convention and you have to map them together regardless. This will leave only one backing field choice for Name, and EF Core will be happy:

modelBuilder.Entity<Company>().Property(c=>c.OwnerName).HasField("m_name");

But if you neglect to map OwnerName to m_name, EF Core 3.0 will report the ambiguous naming issue.

The last change is for backing fields that don’t map to any property yet still need to be persisted. Imagine you have a field, _favoriteEmployee, in your class but no property. Yet you need that field value to get persisted for a reporting system to access:

private string _favoriteEmployee;
public void SetFave(string fave)
{
  _favoriteEmployee=fave;
}

The model still needs to associate the field with a property in order for this to be persisted. You can achieve this by configuring a property and mapping it with HasField to the backing field. For example:

modelBuilder.Entity<Company>()
  .Property<string>("FavoriteEmployee").HasField("_favoriteEmployee");

Interestingly, because you map inferred properties in the same manner as shadow properties, I mistakenly referred to them as shadow properties at first. But shadow properties are for data that’s only in the data store and has no representation—not even a field—in the class.

To avoid issues with ambiguity that developers had been encountering and to allow for cleaner API code, starting with EF Core 3.0, the shadow property name must match the field name exactly. Otherwise it will throw a runtime exception: 

modelBuilder.Entity<Company>()
.Property<string>("_favoriteEmployee").HasField("_favoriteEmployee");

In a follow-up release, you’ll be able to configure field names that don’t match exactly.

Using backing fields to encapsulate properties also extends to navigation properties and properties that are mapped as owned entities (commonly used for value objects).

EF Core enables encapsulation of collections, thanks to it being able to comprehend IEnumerable properties. This was a big deal for DDD practitioners because there was no way to do this in EF6 or earlier versions. I wrote about it in an earlier column, EF Core 1.1: A Few of My Favorite Things (msdn.com/magazine/mt745093). Nothing has changed with EF Core 3.0 in this regard.

Important Changes to Owned Entities in EF Core 3.0

Owned entities (also called owned types) are the feature that allows you to map value objects in EF Core. Owned entities in EF Core were the result of re-thinking the complex type feature that’s been in EF since the beginning. The recipe for owned types in EF Core is as follows:

  • The type has no key property of its own.
  • The type is used as a property of one or more entities (or even another owned entity).
  • The DbContext contains an OwnsOne or OwnsMany mapping that defines the property as an owned type for each entity where it’s used as a property.

I have a PersonFullName type with two string properties (First and Last) and no key property. This type also has other attributes of a value object. You can see its code in the accompanying download. And you’ll find a short primer on value objects in my column at msdn.com/magazine/mt846463.

The PersonFullName value object is used as a property of Employee:

public PersonFullName Name { get; private set; }

For EF Core to persist the value object along with the employee, I need to provide an explicit mapping in the DbContext:

modelBuilder.Entity<Employee>().OwnsOne(e=>e.Name);

All of this was available beginning with EF Core 2.0. A minor but handy fix that arrived in a later version of EF Core is related to constructors. EF Core can instantiate entities if there’s a constructor whose parameters match the properties of the entity. But owned entities didn’t allow this. However, that’s now been fixed, which is especially nice for value objects, as they need their property values at instantiation to avoid creating objects in an invalid state.

EF Core 3.0 Fix for a Significant Owned Entities Problem There was a big flaw in the original behavior of owned entities that has now been fixed in EF Core 3.0. By default, EF Core maps the values of the owned entity to columns in the same table where the owner data is stored. But EF Core required that an owned property (for example, Employee.Name) be populated so that it could read its values (such as First and Last). This meant you could never leave the Name property null even if your business rules allowed it. With the help of some of the EF team members, I came up with a work around that I wrote about in the previously mentioned article.

This problem was not only tied to owned entities. It also affected related entities where the mappings forced a dependent entity’s data to be stored in the principal entity’s table.

A change in EF Core 3.0 fixes this problem. Entities that are owned or are dependents in a one-to-one relationship are now optional. In the case of my PersonFullName value object, if I don’t yet know the name of the new employee (for some strange reason), I can still create and persist an employee object.

Another issue in an earlier version of EF Core that has been corrected was that EF Core didn’t support updating or replacing owned entity properties. But this is a critical pattern to support because value objects are immutable and the owned entity mapping is used for value objects, so the only way to “edit” the owned property is to replace it with a new instance. The issue was fixed in a prior update to EF Core and now the following code (which retrieves an entity, replaces its owned Name property, then saves) will persist correctly:

var employee = context.Employees.FirstOrDefault();
employee.Name=PersonFullName.Create("Diego", "Vega");
context.SaveChanges();

Temporary Workaround for a New Problem There is, unfortunately, a problem arising from the combination of these two fixes: updating owned entities that were originally null. The problem is known (as per this GitHub issue: bit.ly/2maQChH) and is targeted to be fixed in EF Core 3.1.0. In the meantime, if you want to update a null owned entity, Andriy Svyryd from the EF team provides a great workaround (which I’ve tested in a variety of scenarios) in the referenced GitHub issue. The workaround checks to see if the owner (for example, the employee) is also being added. If so, then Added is the correct state for the owned entity, as well. But if not, then the owned entity can’t be new and must therefore have been changed and its state should be marked as Modified.

The workaround takes place in the DbContext SaveChanges override, so your business logic doesn’t need to be aware of the temporary fix or that there’s even a problem. And when the new fix arrives, you’ll only need to remove the extra code in DbContext and won’t have to change anything in your business logic. The workaround leverages a newly exposed method called FindOwnership that will return detailed information about an owned entity. I modified the workaround a bit using the IsOwned method and my version is shown in Figure 1.

Figure 1 Override SaveChanges as a Temporary Workaround for a Problem with Replacing Null Owned Entities

public override int SaveChanges () {
  foreach (var entry in ChangeTracker.Entries ()
          .Where (e => e.Metadata.IsOwned () && e.State == EntityState.Added)) {
    var ownership = entry.Metadata.FindOwnership ();
    var parentKey = ownership.Properties
                     .Select (p => entry.Property (p.Name).CurrentValue).ToArray ();
    var parent = this.Find (ownership.PrincipalEntityType.ClrType, parentKey);
    if (parent != null) {
      var parentEntry = this.Entry (parent);
      if (parentEntry.State != EntityState.Added) {
        entry.State = EntityState.Modified;
      }
  }
  return base.SaveChanges ();
}

EF Core Keeps Improving Mappings for DDD

Each iteration of EF Core has brought improvements that enable it to more easily map our nicely designed DDD-influenced domain models. While there haven’t been a lot of new features added to EF Core 3.0, a lot of work was done to tighten up the APIs. The team thinks of this as a “foundational” version as it sets the stage for the continued enhancement of EF Core. They’re very open to ideas for improvements related to mapping domain models in order to minimize the need to build explicit data models when EF Core’s mappings aren’t sufficient to the task.

I hope these columns have helped you explore new technologies, expand your knowledge and further your careers! Feel free to reach out to me via my blog at thedatafarm.com. If you want to keep up with me, I send out an occasional newsletter to share articles, upcoming conferences, videos and training opportunities. You can find information about that on my Web site, as well. Thank you for the wonderful opportunity that this column has given me to learn and share with you.


Julie Lerman is a Microsoft Regional Director, Microsoft MVP, Docker Captain and software team coach who lives in the hills of Vermont. You can find her presenting on data access and other topics at user groups and conferences around the world. She blogs at thedatafarm.com/blog and is the author of “Programming Entity Framework,” as well as a Code First and a DbContext edition, all from O’Reilly Media. Follow her on Twitter: @julielerman and see her Pluralsight courses at bit.ly/PS-Julie.

Thanks to the following Microsoft technical expert for reviewing this article: Diego Vega