Entity Framework 4.2

Entity types supported by the Entity Framework

I was going to write a post about when to use change-tracking proxies. But I then thought before doing that it would be useful to go over all the different types of classes that the Entity Framework supports, of which change-tracking proxies is one. So here they are, in chronological order of when they were implemented/introduced.

Entities derived from EntityObject*

The only type of entity supported in initial preview versions of the EF were those that derived from the EF EntityObject class. EntityObject provided several services for entities including those for change tracking property values, managing relationships, and handling the entity's key. This, in principle, allowed entities to be handled very efficiently by the EF.

The downside of this approach (and it was a BIG downside) was that it resulted in a very tight coupling of business objects (the entities) to the data access layer (the EF), and therefore went completely against the principal of persistence ignorance. Also, in practice, the implementation of EntityObject made entities derived from it very hard to understand and full of EF-specific code.

Entities types derived from EntityObject are supported by EF1 and EF4, but not by DbContext and Code First as shipped in the EF4.x versions.

IPOCO entities*

The EntityObject class underwent some refactoring before EF1 was released in .NET 3.5sp1. Three interfaces were extracted from it: IEntityWithRelationships, IEntityWithChangeTracker, and IEntityWithKey. These were collectively known as the IPOCO interfaces. The intention was to provide some level of decoupling between entity types and the EF. However, the reality was that the coupling still existed through the interfaces and the interfaces were hard to implement correctly such that by the time you did it you may as well just have used EntityObject anyway.

IPOCO entities are theoretically supported by EF1, EF4, and EF4.x, but in reality I have never seen any application that uses them. If you know of one I'd love to hear about it! (Change-tracking proxies don't count.)

POCO entities

POCO stands for Plain Old CLR Object and refers to classes that aren't coupled to anything. In other words, they don't have to derive from anything, implement anything, or reference anything except normal CLR stuff—they are plain old CLR objects.

Support for POCO entities is critical for any semblance of persistence ignorance—the decoupling of business objects from the data access layer. Support for POCO entities was implemented as one of the first features of EF4 and they continue to be supported by all later versions.

Lazy loading proxies

The decoupling of the entity types from the EF that was enabled by POCO support is a very good thing. However, there is a price to pay—the entities now no longer have access to the EF infrastructure to do useful things. One of those useful things is lazy loading of related entities the first time they are accessed—see here for more details. The entity can't ask EF to load related entities from the database if it doesn't have access to EF.

Lazy loading proxies solve this problem by dynamically generating classes at runtime that derive from the POCO entity types. These dynamically generated classes have a reference to the EF and override virtual navigation properties such that accesses to the properties can be intercepted and lazy loading by the EF can be triggered. Instances of these proxy types are then created and returned to the caller instead of just instances of the entity types themselves.

Support for lazy loading proxies was implemented alongside POCO support in EF4 and they continue to be supported by all later versions. The DbContext T4 templates generate entity types that will act as lazy loading proxies.

Change-tracking proxies

One of the key tasks of the EF is to keep track of what changes have been made to entities and their relationships so that the correct updates can be sent to the database when SaveChanges is called. For most POCO entity types, including lazy loading proxies, this happens through snapshot change-tracking. That is, a snapshot of the entity is taken when it enters the context and then later that snapshot it compared to the current graph to figure out what changes have been made.

Snapshot change-tracking works great, but there may be situations where it is better to detect changes to properties and relationships immediately. This can be done by change-tracking proxies. Change-tracking proxies are like lazy loading proxies except that every property getter and setter must be virtual and is then overridden in the proxy type. This means that any change made to any scalar or navigation property can be detected immediately.

Interestingly, the way change tracking proxies do this is by implementing two of the IPOCO interfaces mentioned above—specifically, IEntityWithChangeTracker for tracking changes to scalar properties and IEntityWithRelationships for tracking changes to relationships between entities. This is why you may see code that checks whether or not an entity implements one of these interfaces in order to check whether or not it is a change-tracking proxy.

Support for change-tracking proxies was implemented towards the end of the EF4 cycle and first released in EF4. They continue to be supported by all later versions. The EF4 POCO templates generate entity types that will act as change-tracking proxies.

Summary

EF1 (in .NET 3.5sp1) supported only EntityObject-derived entities and IPOCO. Neither of these are really used anymore with DbContext in EF4.x versions. EF4 and above support POCO entities, including support for lazy loading proxies and change-tracking proxies.

So which type of entity should I use? I'll try to answer that next time…

*Disclaimer: EntityObject and IPOCO were both before my time on the team—my first job on the EF team was implementing POCO support. So if I got some of the history wrong, then I apologize now.


This page is up-to-date as of December 5th, 2011. Some things change. Some things stay the same. Use your noggin.