Following Domain Driven Design (DDD) principles [Evans, DDD], the domain should be represented by objects with state and behavior, using a rich object-oriented model. Additionally, in n-tier applications it is ideal to reuse as many objects as you could in order to reduce code duplication.
However, the object’s behavior is usually very different in each tier; for example, in the business tier the behavior is often business-oriented and it shouldn’t be executed in the presentation tier.
To solve this problem, we can use POCOs with only state (properties), and add behavior to them using extension methods in the business tier.
| Note: Although extension methods provide a good extensibility mechanism, they have some limitations. For example, they don’t support late-bound polymorphism (virtual methods). |
In the following code snippet we can see the Order and Product POCOs, related each other through the Product and the Product_ID properties.
namespace Common.Domain.Entities
{
public class Order
{
public int Id { get; set; }
public Product Product { get; set; }
public int Product_ID { get; set; }
public int Quantity { get; set; }
...
}
public class Product
{
public int Id { get; set; }
public string Description { get; set; }
public int Stock { get; set; }
...
}
}
| Note: EF supports two types of associations: Independent Associations (Product property) and Foreign Key Associations (Product_ID property). While the first ones are the most popular because are more object-oriented, the second ones are very useful in “disconnected” scenarios (e.g. when you need to update the relationship and you don’t have access to the EF context). |
And as we mentioned before, the behavior of both objects is added using the extension methods defined in the following classes.
namespace Business.Domain.Entities
{
public static class OrderExtensions
{
public static void Confirm(this Order order) { ... }
public static void Cancel(this Order order) { ... }
...
}
public static class ProductExtensions
{
public static void SubstractStock(this Product product) { ... }
public static void RestoreStock(this Product product) { ... }
...
}
}
This allows us to call the specific domain behavior using the entity instance.
order.Confirm();
It is also important to mention that there are some scenarios where the entity does not match with the data that should be shown in the presentation layer, e.g. let’s say it is required to show the customer’s name and the description of the latest ten products that he or she ordered. In those cases it could be a better option to create a customized Data Transfer Object (DTO) in order to transfer over the wire only the data needed.

| Note: If your architecture must support “cross-process change tracking”, I recommend you to use the “self-tracking entities” EF feature, an excellent feature designed for n-tier applications. Since it increases the amount of data that is sent over the wire, you should use this feature only if it is required. |
References:
- Evans, DDD: Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software, Boston, MA: Addison-Wesley 2004.