Persistence Ignorance in ADO.NET Entity Framework

I previously published a JSON / POX Filter for MVC developers working with RESTful services. It works really well in that it allows a Controller Action to speak two additional languages (JSON and XML) other than View rendition without requiring any extra modifications. Everything was fine until I pulled out Linq to SQL and plugged in Entity Framework and got an education on a variety of issues with the framework.

Persistence Ignorance

Serializing objects within the Entity Framework is a common enough scenario that I expected to work around it farily easily. More so because the serialized objects only contained some additional undesirable key/value pairs that I did not expect. This is when I first got introduced to Persistence Ignorance.

In the Entity Framework an object generated from the Persons table for example contains not only the properties and relationships of that table (such as Age and Name) but also has additional properties used for tracking changes to the object (such as EntityState). In my scenario, serializing the entity object ought to have resulted in a plain object representation (JSON format shown):

// Plain Old CLR Object
{"Id":1, "Name":"John"}

But instead I saw this:

// Entity Object
{"Id":1, "Name":"John",
 "EntityState":2, "EntityKey": {"EntitySetName":"Persons",
    "EntityContainerName":"PersonEntities","EntityKeyValues":
     [{"Key":"Id","Value":1}],"IsTemporary":false}}

In laymen’s terms Persistence Ignorance is a design principle which suggests that the underlying object hide the details of how it is persisted so you can ignore it and work with a simple object. The term “ignorance” suggests that this behaviour be encapsulated which is a tenet of Object Oriented design.

Single Responsibility Principle

Instead, the Entity Object has additional properties used by the Entity Framework for managing data persistence. An object that plainly represents the Person table and does not contain any additional service-level properties and functions is called a Plain Old CLR Object or POCO. The Entity Object violates the Single Responsibility Principle because other than representing a Person it takes on the additional responsibility of managing data persistence.

Albeit, this makes it very convenient for the Entity Framework to persist the object in the database if, for example, you make modifications to the Person object and save it back to the database. Because the state information is stored within the object itself, the Entity Framework easily knows if the object has changed (by looking at the EntityState property) and what changes were made. It can then update the appropriate fields in the database. Even though this makes things easy for the Entity Framework, it is clearly a big second responsibility tacked on to what should be a plain old Person object. Besides, developers need not be confused by nor concerned with lower level implementation details of state and persistence. Consequently, the Entity Framework recognizes and intends to fix this in Version 2 which will support POCO and Persistence Ignorance.

Domain Driven Design

Lack of POCO objects means that developers are left dealing with an Entity Object and while for me this started off with a naive problem of serializing a Person object, the actual issue has further implications. My over simplified understanding of Domain Driven Design is that domain objects should be Plain Old CLR Objects and should encapsulate only domain logic. So for example, if you are building a warehousing application, the objects used to represent the warehouse domain should only encapsulate functionality within the warehouse (such as orders, storage and delivery). Anything more in the objects (such as database persistence) and the application breaks the Domain Driven Design model. It gets much harder to manage or extend, and Separation of Concerns is lost. For further discussion Ian Cooper’s article on Entity Framework and Domain Drive Design provides an interesting and insightful background on this issue.

An Interim Solution

The EFPocoAdapater is just what the name suggests — a POCO adapter for the Entity Framework which solves the issues outlined above. The EFPocoAdapter currently serves as a sort of staging platform for supporting these scenarios until they become available in version 2 of the Entity Framework, at which time EFPocoAdapter will be made obsolete.

3 Responses



This article is no longer open for comments