What Will I Learn?
You will learn Modeling domains with The Entity Framework Data Model
Requirements
Entity Framework
Difficulty
Intermediate
How To Modeling domains with The Entity Framework Data Model
The Entity Framework Data Model lets developers create an object oriented model of the data their applications need and Object Oriented Programming really becomes a first class citizen in the Microsoft data access technology stack.
The Entity Data Model is a powerful modeling tool and as usual; with great power comes great responsibilities and we as developers need some initial guidelines and best practices to lead our way into this new object oriented data access modeling.
Model boundaries – the aggregate
One of the most frequently asked questions I see when I hover the forums on EDM topics is - "my model is slow when I drag my 150 tables into the designer". For these developers I would like to share a first advice of best practices: "Avoid huge models in the first place".
Huge models have a tough disadvantage, it’s really hard to tell where the scope of a transaction starts and ends. With interconnected relationships and lots of classes in a hierarchy, how can you be certain that you actually have set the right boundaries for the current transaction? How can you be sure that you aren’t touching more than you need?
When you create a model what you should strive for is to capture a well defined and limited concept that you know will fit into a business transaction of the case you are currently trying to solve. In modeling terms what you want is an Aggregate [Evans] with a root entity and a boundary. What I’ve found is that an EDM never should be larger than one, maybe two closely related, such aggregates to be maintainable. So instead of one huge EDM, go for several smaller ones that each capture a specific concept of your application.
Figure 1: An aggregate
An added benefit is that the model will be easier to grasp and you’ll be able to understand and focus on single concepts much quicker.
Figure 2: Picture of Small conceptual EDM's in a Solution tree
Another common mistake that I see developers do is to assume that every sub-part of a project looks at a model the same way but the fact in the matter is that most don’t. The shipping sub system of your application might use and need an Order, but more often than not it’s a slightly different Order than the same concept in the Order management part of your applications. It’s the same data, agreed, but it’s often looked upon in a different way.
The shipping subsystem might need the order address and what products that it should send, but it’s not necessarily interested in billing information or financial information. Re-using the order model in both subsystems clearly violates the "Interface Segregation Principle" that says: "Clients should not be forced to depend upon interfaces that they do not use". Evans also recognizes this and in the part "Strategic design" of his book he extensively talks about "Bounded context".
A bounded context is a boundary for a model that applies for a certain context or concept. So when building our model we should not chase after re-use to in extreme. If a concept looks at a piece of data differently than another concept, chances are that you will be better of creating two separate models than trying to squeeze in as much of both concepts as possible into a single model.
Normalizing the model
When we work with databases we usually closely follow normalization rules that are there, amongst other reasons, to minimize structural and data duplication. When we create Object Oriented models we should try to normalize for maximum reuse as well. The current version of the EDM supports two such modeling techniques - value objects and inheritance - but unfortunately the designer doesn’t.
So to be able to get to the more advanced modeling we need to fire up the good old XML editor and write the EDM conceptual, structural and mapping files by hand.
Value objects
One way to normalize an object oriented model is to re-use classes. In the domain driven world this is called a "Value object" and in the Entity Framework it is called a "Complex type". The idea is simple; you got a concept that doesn’t have its own ID and a concept that is shared through multiple models; a classic such example is an Address. Address should probably be handled, as a concept, in the same manner for an Order shipping address as for a Customer billing address. The basics are the same: You got a street, zip code and country; and validation is probably the same as well. So why spend time in writing several address representations? Why not just reuse the one you already got?
As mentioned, in Entity Framework you utilize this with the notion of a "Complex type", like the following example:
Listing 1: A complex type mapping
<EntityType Name="Customer">
<Key>
<PropertyRef Name="CustomerID" />
</Key>
<Property Name="CustomerID" Type="String" Nullable="false" MaxLength="5"
Unicode="true" FixedLength="true" />
<Property Name="CompanyName" Type="String" Nullable="false" MaxLength="40"
Unicode="true" FixedLength="false" />
<Property Name="ContactName" Type="String" MaxLength="30" Unicode="true"
FixedLength="false" />
<Property Name="ContactTitle" Type="String" MaxLength="30" Unicode="true"
FixedLength="false" />
<Property Name="Phone" Type="String" MaxLength="24" Unicode="true"
FixedLength="false" />
<Property Name="Address" Type="Self.Address" Nullable="false" />
<Property Name="Fax" Type="String" MaxLength="24" Unicode="true"
FixedLength="false" />
</EntityType>
<ComplexType Name="Address">
<Property Name="AddressLine" Type="String" MaxLength="60" Unicode="true"
FixedLength="false" />
<Property Name="City" Type="String" MaxLength="15" Unicode="true"
FixedLength="false" />
<Property Name="Region" Type="String" MaxLength="15" Unicode="true"
FixedLength="false" />
<Property Name="PostalCode" Type="String" MaxLength="10" Unicode="true"
FixedLength="false" />
<Property Name="Country" Type="String" MaxLength="15" Unicode="true"
FixedLength="false" />
</ComplexType>
<EntityType Name="Order">
<Key>
<PropertyRef Name="OrderID" />
</Key>
<Property Name="OrderID" Type="Int32" Nullable="false" />
<Property Name="CustomerID" Type="String" MaxLength="5" Unicode="true"
FixedLength="true" />
<Property Name="EmployeeID" Type="Int32" />
<Property Name="OrderDate" Type="DateTime" />
<Property Name="RequiredDate" Type="DateTime" />
<Property Name="ShippedDate" Type="DateTime" />
<Property Name="ShipVia" Type="Int32" />
<Property Name="Freight" Type="Decimal" Precision="19" Scale="4" />
<Property Name="ShipName" Type="String" MaxLength="40" Unicode="true"
FixedLength="false" />
<Property Name="ShippingAddress" Type="Self.Address" Nullable="false" />
</EntityType>
Which results in something like:
Figure 3: Reusing a Value Type
What we see in figure 3 is the possibility to have one conceptual address and the reuse it in multiple aggregates. The benefit of this is that now I can reuse my validation logic for all addresses in my application.
What we’ve seen is that the conceptual model in Entity Framework really is, and should be, a separate model from the storage ditto. It enables advanced object oriented design and lets you model your application code in a way that best suites you.
Posted on Utopian.io - Rewarding Open Source Contributors