Skip to main content

September 2017
Volume 32 Number 9

Data Points - DDD-Friendlier EF Core 2.0

By Julie Lerman | September 2017 | Get the Code: C#    VB

Julie LermanIf you’ve been following this column for a while, you may have noticed quite a few articles about implementing Entity Framework (EF) when building solutions that lean on Domain-Driven Design (DDD) patterns and guidance. Even though DDD is focused on the domain, not on how data is persisted, at some point you need data to flow in and out of your software.

In past iterations of EF, its patterns (conventional or customized) have allowed users to map uncomplicated domain classes directly to the database without too much friction. And my guidance has generally been that if the EF mapping layer takes care of getting your nicely designed domain models into and out of the database without having to create an additional data model, this is sufficient. But at the point when you find yourself tweaking your domain classes and logic to make them work better with Entity Framework, that’s a red flag that it’s time to create a model for data persistence and then map from the domain model classes to the data model classes.

I was a little surprised to realize how long ago those articles about DDD and EF mappings came out. It’s been four years since I wrote the three-part series called “Coding for Domain-Driven Design: Tips for Data-Focused Devs,” which span the August, September and October 2013 issues of MSDN Magazine. Here’s a link to the first part, which includes links to the entire series: msdn.com/magazine/dn342868.

There were two specific columns that addressed DDD patterns and explained how EF did or didn’t easily map between your domain classes and database. As of EF6, one of the biggest issues was the fact that you couldn’t encapsulate and thereby protect a “child” collection. Using the known patterns for protecting the collection (most often this meant em-ploying an IEnumerable) didn’t align with EF’s requirements, and EF wouldn’t even recognize that the navigation should be part of the model. Steve Smith and I spent a lot of time thinking about this when we created our Pluralsight course, Domain-Driven Design Fundamentals ( bit.ly/PS-DDD) and eventually Steve came up with a nice workaround ( bit.ly/2ufw89D).

EF Core finally solved this problem with version 1.1 and I wrote about this new feature in the January 2017 column ( msdn.com/magazine/mt745093). EF Core 1.0 and 1.1 also resolved a few other DDD constraints but left some gaps—most notably the inability to map DDD value objects used in your domain types. The ability to do this had existed in EF since its beginning, but it hadn’t yet been brought to EF Core. But with the upcoming EF Core 2.0, that limitation is now gone.

What I’m going to do in this article is lay out the EF Core 2.0 features available to you that align with many of the DDD concepts. EF Core 2.0 is much friendlier to developers who are leveraging these concepts and perhaps it will introduce you to them for the first time. Even if you don’t plan to embrace DDD, you can still benefit from its many great patterns! And now you can do that even more with EF Core.

One-to-One Gets Smarter

In his book, “Domain-Driven Design,” Eric Evans says, “A bidirectional association means that both objects can be un-derstood only together. When application requirements do not call for traversal in both directions, adding a traversal di-rection reduces inter­dependence and simplifies the design.” Following this guidance has indeed removed side effects in my code. EF has always been able to handle uni-directional relationships with one-to-many and one-to-one. In fact, while writing this article, I learned that my longtime misunderstanding that a one-to-one relationship with both ends required forces you into a bi-directional relationship was wrong. However, you did have to explicitly configure those required rela-tionships, and that’s something you don’t have to do now in EF Core, except for with edge cases.

An unfavorable requirement in EF6 for one-to-one relationships was that the key property in the dependent type had to double as the foreign key back to the principal entity. This forced you to design classes in an odd way, even if you got used to it. Thanks to the introduction of support for unique foreign keys in EF Core, you can now have an explicit foreign key property in the dependent end of the one-to-one relationship. Having an explicit foreign key is more natural. And in most cases, EF Core should be able to correctly infer the dependent end of the relationship based on the existence of that foreign key property. If it doesn’t get it right because of some edge case, you’ll have to add a configuration, which I’ll demonstrate shortly when I rename the foreign key property.

To demonstrate a one-to-one relationship, I’ll use my favorite EF Core domain: classes from the movie “Seven Samu-rai”:

public class Samurai {
  public int Id { get; set; }
  public string Name { get; set; }
  public Entrance Entrance { get; set; }
}

public class Entrance {
  public int Id { get; set; }
  public string SceneName { get; set; }
  public int SamuraiId { get; set; }
}

Now with EF Core, this pair of classes—Samurai and Entrance (the character’s first appearance in the movie)—will be correctly identified as a uni-directional one-to-one relationship, with Entrance being the dependent type. I don’t need to include a navigation property in the Entrance and I don’t need any special mapping in the Fluent API. The foreign key (SamuraiId) follows convention, so EF Core is able to recognize the relationship.

EF Core infers that in the database, Entrance.SamuraiId is a unique foreign key pointing back to Samurai. Keep in mind something I struggled with because (as I have to continually remind myself), EF Core is not EF6! By default, .NET and EF Core will treat the Samurai.Entrance as an optional property at run time unless you have domain logic in place to enforce that Entrance is required. Starting with EF4.3, you had the benefit of the validation API that would respond to a [Required] annotation in the class or mapping. But there is no validation API (yet?) in EF Core to watch for that particular problem. And there are other requirements that are database-related. For example, Entrance.SamuraiId will be a non-nullable int. If you try to insert an Entrance without a SamuraiId value populated, EF Core won’t catch the invalid data, which also means that the InMemory provider currently doesn’t complain. But your relational database should throw an error for the constraint conflict.

From a DDD perspective, however, this isn’t really a problem because you shouldn’t be relying on the persistence layer to point out errors in your domain logic. If the Samurai requires an Entrance, that’s a business rule. If you can’t have or-phaned Entrances, that’s also a business rule. So the validation should be part of your domain logic anyway.

For those edge cases I suggested earlier, here’s an example. If the foreign key in the dependent entity (for example, Entrance) doesn’t follow convention, you can use the Fluent API to let EF Core know. If Entrance.SamuraiId was, perhaps Entrance.SamuraiFK, you can clarify that FK via:

modelBuilder.Entity<Samurai>().HasOne(s=>s.Entrance)
  .WithOne().HasForeignKey<Entrance>(e=>e.SamuraiFK);

If the relationship is required on both ends (that is, Entrance must have a Samurai) you can add IsRequired after WithOne.

Properties Can Be Further Encapsulated

DDD guides you to build aggregates (object graphs), where the aggregate root (the primary object in the graph) is in control of all of the other objects in the graph. That means writing code that prevents other code from misusing or even abusing the rules. Encapsulating properties so they can’t be randomly set (and, often, randomly read) is a key method of protecting a graph. In EF6 and earlier, it was always possible to make scalar and navigation properties have private setters and still be recognized by EF when it read and updated data, but you couldn’t easily make the properties private. A post by Rowan Miller shows one way to do it in EF6 and links back to some earlier workarounds ( bit.ly/2eHTm2t). And there was no true way to protect a navigation collection in a one-to-many relationship. Much has been written about this latter problem. Now, not only can you easily have EF Core work with private properties that have backing fields (or inferred backing fields), but you can also truly encapsulate collection properties, thanks to support for mapping IEnumerable<T>. I wrote about the backing fields and IEnumerable<T> in my previously mentioned January 2017 column, so I won’t rehash the details here. However, this is very important to DDD patterns and therefore relevant to note in this article.

While you can hide scalars and collections, there’s one other type of property you may very well want to encapsulate—navigation properties. Navigation collections benefit from the IEnumerable<T> support, but navigation properties that are private, such as Samurai.Entrance, can’t be comprehended by the model. However, there is a way to configure the model to comprehend a navigation property that’s hidden in the aggregate root.

For example, in the following code I declared Entrance as a private property of Samurai (and I’m not even using an explicit backing field, though I could if needed). You can create a new Entrance with the CreateEntrance method (which calls a factory method in Entrance) and you can only read an Entrance’s SceneName property. Note that I’m employing the C# 6 null-conditional operator to prevent an exception if I haven’t yet loaded the Entrance:

private Entrance Entrance {get;set;}
public void CreateEntrance (string sceneName) {
    Entrance = Entrance.Create (sceneName);
  }
public string EntranceScene => Entrance?.SceneName;

By convention, EF Core won’t make a presumption about this private property. Even if I had the backing field, the private Entrance wouldn’t be automatically discovered and you wouldn’t be able to use it when interacting with the data store. This is an intentional API design to help protect you from potential side effects. But you can configure it explicitly. Remember that when Entrance is public, EF Core is able to comprehend the one-to-one relationship. However, because it’s private you first need to be sure that EF knows about this.

In OnModelCreating, you need to add the HasOne/WithOne fluent mapping to make EF Core aware. Because Entrance is private, you can’t use a lambda expression as a parameter of HasOne. Instead, you have to describe the property by its type and its name. WithOne normally takes a lambda expression to specify the navigation property back to the other end of the pairing. But Entrance doesn’t have a Samurai navigation property, just the foreign key. That’s fine! You can leave the parameter empty because EF Core now has enough information to figure it out:

modelBuilder.Entity<Samurai> ()
  .HasOne (typeof (Entrance), "Entrance").WithOne();

What if you use a backing property, such as _entrance in the Samurai class, as shown in these changes:

private Entrance _entrance;
private Entrance Entrance { get{return _entrance;} }
public void CreateEntrance (string sceneName) {
    _entrance = _entrance.Create (sceneName);
  }
public string EntranceScene => _entrance?.SceneName;

EF Core will figure out that it needs to use the backing field when materializing the Entrance property. This is because, as Arthur Vickers explained in the very long conversation we had on GitHub while I was learning about this, if "there is a backing field and there is no setter, EF just uses the backing field [because] there is nothing else it can use." So it just works.

If that backing field name doesn’t follow convention, if, for example, you named it _foo, you will need a metadata con-figuration:

modelBuilder.Entity<Samurai> ()
  .Metadata
  .FindNavigation ("Entrance")
  .SetField("_foo");

Now updates to the database and queries will be able to work out that relationship. Keep in mind that if you want to use eager loading, you’ll need to use a string for Entrance becaise it can’t be discovered by the lambda expression; for example:

var samurai = context.Samurais.Include("Entrance").FirstOrDefault();

You can use the standard syntax for interacting with backing fields for things like filters, as shown at the bottom of the Backing Fields documentation page at bit.ly/2wJeHQ7.

Value Objects Are Now Supported

Value objects are an important concept for DDD as they allow you to define domain models as value types. A value ob-ject doesn’t have its own identity and becomes part of the entity that uses it as a property. Consider the string value type, which is made up of a series of characters. Because changing even a single character changes the meaning of the word, strings are immutable. In order to change a string, you must replace the entire string object. DDD guides you to consider using value objects anywhere you’ve identified a one-to-one relationship. You can learn more about value ob-jects in the DDD Fundamentals course I mentioned earlier.

EF always supported the ability to include value objects through its ComplexType type. You could define a type with no key and use that type as a property of an entity. That was enough to trigger EF to recognize it as a ComplexType and map its properties into the table to which the entity is mapped. You could then extend the type to also have features re-quired of a value object, such as ensuring the type is immutable and a means to assess every property when determining equality and overriding the Hash. I often derive my types from Jimmy Bogard’s ValueObject base class to quickly adopt these attributes.

A person’s name is a type that’s commonly used as a value object. You can ensure that any time someone wants to have a person’s name in an entity, they always follow a common set of rules. Figure 1 shows a simple PersonName class that has First and Last properties—both fully encapsulated—as well as a property to return a FullName. The class is designed to ensure both parts of the name are always supplied.

Figure 1 The PersonName Value Object
public class PersonName : ValueObject<PersonName> {
  public static PersonName Create (string first, string last) {
    return new PersonName (first, last);
  }
  private PersonName () { } 
  private PersonName (string first, string last) {
    First = first;
    Last = last;
  }
  public string First { get; private set; }
  public string Last { get; private set; }
  public string FullName => First + " " + Last;
}

I can use PersonName as a property in other types and continue to flesh out additional logic in the PersonName class. The beauty of the value object over a one-to-one relationship here is that I don’t have to maintain the relationship when I’m coding. This is standard object-oriented programming. It’s just another property. In the Samurai class, I’ve add a new property of this type, made its setter private and provided another method named Identify to use instead of the setter:

 

public PersonName SecretIdentity{get;private set;}
public void Identify (string first, string last) {
  SecretIdentity = PersonName.Create (first, last);
}

Until EF Core 2.0, there was no feature similar to ComplexTypes, so you couldn’t easily use value objects without add-ing in a separate data model. Rather than just reimplement the ComplexType in EF Core, the EF team created a concept called owned entities, which leverages another EF Core feature, shadow properties. Now, owned entities are recognized as additional properties of the types that own them and EF Core understands how they resolve in the database schema and how to build queries and updates that respect that data.

EF Core 2.0 convention won’t automatically discover that this new SecretIdentity property is a type to be incorporated into the persisted data. You’ll need to explicitly tell the DbContext that the Samurai.SecretIdentity property is an owned entity in DbContext.OnModelCreating using the OwnsOne method:

protected override void OnModelCreating (ModelBuilder modelBuilder) {
  modelBuilder.Entity<Samurai>().OwnsOne(s => s.SecretIdentity);
}

This forces the properties of PersonName to resolve as properties of Samurai. While your code will use the Samurai.SecretIdentity type and navigate through that to the First and Last properties, those two properties will resolve as columns in the Samurais database table. EF Core convention will name them with the name of the property in Samurai (SecretIdentity) and the name of the owned entity property, as shown in Figure 2.

The Schema of the Samurais Table, Including the Properties of the Value
Figure 2 The Schema of the Samurais Table, Including the Properties of the Value

Now I can identify a Samurai’s secret name and save it with code similar to this:

using (var context = new SamuraiContext()) {
  var samurai = new Samurai { Name = "HubbieSan" 
  samurai.Identify ("Late", "Todinner");
  context.Samurais.Add (samurai);
  context.SaveChanges ();
}

In the data store, "Late" gets persisted into the SecretIdentity_First field and "Todinner" into the SecretIdentity_Last field.

Then I can simply query for a Samurai:

var samurai=context.Samurais .FirstOrDefaultAsync (s => s.Name == "HubbieSan")

EF Core will assure that the resulting Samurai’s SecretIdentity property is populated and I can then see the identity by requesting:

samurai.SecretIdentity.FullName

EF Core requires that properties that are owned entities are populated. In the sample download, you’ll see how I designed the PersonName type to accommodate that.

Simple Classes for Simple Lessons

What I’ve shown you here are simple classes that leverage some of the core concepts of a DDD implementation in the most minimal way that lets you see how EF Core responds to those constructs. You’ve seen that EF Core 2.0 is able to comprehend one-to-one uni-directional relationships. It can persist data from entities where scalar, navigation and collection properties are fully encapsulated. It also allows you to use value objects in your domain model and is able to persist those, as well.

For this article, I’ve kept the classes simple and lacking in additional logic that more correctly constrains the entities and value objects using DDD patterns. This simplicity is reflected in the download sample, which is also on GitHub at bit.ly/2tDRXwi. There you’ll find both the simple version and an advanced branch where I’ve tightened down this domain model and applied some additional DDD practices to the aggregate root (Samurai), its related entity (Entrance) and the value object (PersonName) so you can see how EF Core 2.0 handles a more realistic expression of a DDD aggregate. In an upcoming column, I’ll discuss the advanced patterns applied in that branch.

Please keep in mind that I’m using a version of EF Core 2.0 shortly before its final release. While most of the behaviors I’ve laid out are solid, there’s still the possibility of minor tweaks before 2.0.0 is released.


Julie Lerman is a Microsoft Regional Director, Microsoft MVP, software team mentor and consultant 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 juliel.me/PS-Videos.