Page 18 - MSDN Magazine, September 2017
P. 18

In OnModelCreating, you need to add the HasOne/WithOne fluent mapping to make EF Core aware. Because Entrance is pri- vate, you can’t use a lambda expression as a parameter of HasOne. Instead,youhavetodescribethepropertybyitstypeanditsname. WithOne normally takes a lambda expression to specify the navi- gation 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 isnothingelseitcanuse.”Soitjustworks.
If that backing field name doesn’t follow convention, if, for example, you named it _foo, you will need a metadata configuration:
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/2vgDwPk.
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 object doesn’t have its own identity and becomes part of the entity that uses it as a prop- erty. 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
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 thetabletowhichtheentityismapped.Youcouldthenextend the type to also have features required of a value object, such as ensuring the type is immutable and a means to assess every prop- erty 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.
Until EF Core 2.0, there was no feature similar to complex types, so you couldn’t easily use them without adding in a separate data model.
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 adding in a sepa- rate 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);
}
Figure 2 The Schema of the Samurais Table, Including the Properties of the Value Object
to consider using value objects anywhere you’ve identified a one-to-one relationship. You can learn more about value objects in the DDD Fundamentals course I mentioned earlier.
EF always supported the ability to include value objects through
14 msdn magazine
Data Points



































































   16   17   18   19   20