Volume 26 Number 07
Data Points - Demystifying Entity Framework Strategies, Part 3: Classes, Queries and Contexts
By Julie Lerman | July 2011
This is the third in a series of Data Points columns aimed at helping you make some important decisions when using the Entity Framework as your data access layer in your applications. The first, about model creation workflow, in the May 2011 issue (bit.ly/lOcjPz), discussed choosing among the Code First, Model First and Database First workflows. Code First doesn’t use a visual model, but Database First and Model First do. One of the targeted choices in this column will focus on the code generation options when you have a visual model from which you’ll create your domain classes. While on the topic of code generation, I’ll take a quick look at choosing between using the ObjectContext and DbContext and choosing between LINQ to Entities and Entity SQL.
Generated Classes: EntityObjects or POCOs?
The first version of the Entity Framework (EF hereafter for brevity) relied on the EntityObject class to enable entities to interact with the ObjectContext as it managed relationships and tracked changes to entity instances. The code generation ensured that the classes generated from your model inherited from EntityObject. This is still the default with Visual Studio 2010, but now you have another option. In the Microsoft .NET Framework 4, the EF and its ObjectContext gained the ability to track changes and manage relationships among entities without depending on the EntityObject to send notifications to the ObjectContext. That means your classes no longer have to inherit from EntityObject, which makes a huge difference for developers who are interested in persistence ignorance, separation of concerns, unit testing and other software practices that fall under the generalized umbrella of Agile development.
Classes that don’t rely on other APIs are referred to as Plain Old CLR Objects, or POCOs. The EF ability to use these cleaner classes but still perform its change tracking and other entity management tasks is referred to as its “POCO support.” This support provides the backbone for Code First. Because the EF is able to work with POCO entities, classes you create in the Code First scenario can also be managed by the EF context.
So if the EF relies on the EntityObject notifying the context of changes to the entities, how is it possible to have POCOs that not only don’t inherit from EntityObject, but have no knowledge of the EF? The EF uses two paths to let developers have their proverbial cake and eat it too. One thing that doesn’t change is that the ObjectContext still needs to be aware of what classes it’s responsible for.
The first path to POCO support results from the ObjectContext getting even smarter as of the .NET Framework 4. Now the context is able to inspect the classes it’s managing. It has new methods such as DetectChanges that will read the objects it’s managing and then update the state information that it tracks for those objects.
The second way the EF lets you use POCOs while still benefiting from the framework uses a bit of sleight of hand in the form of proxy objects. If every one of the POCO class properties is marked virtual, the EF runtime will create a proxy (wrapper) around the object and that proxy does the same job as the EntityObject. The proxy class will notify the context of property and relationship changes. You can also leverage the proxies without affecting the entire class. The EF will be able to lazy load navigation properties that are marked virtual, even when the other properties are not.
Figure 1 shows a visual representation of the three ways now available for the ObjectContext to keep track of entity changes, using EntityObjects or one of the two POCO mechanisms.
Figure 1 How Entity Framework Tracks Changes to Entities
ObjectContext or DbContext?
The EF 4.1 introduced a lightweight version of the ObjectContext called DbContext. It provides all of the same POCO support as the ObjectContext. DbContext also wraps some of the more complex logic required for coding against the ObjectContext into simpler methods and properties, making it easier to execute the most common coding tasks in the EF.
The DbContext is the default context to use with Code First classes, but the ObjectContext is the default with Database First and Model First. Microsoft provides alternate code generation templates for the latter two models. The first is the ADO.NET POCO Entity Generator. This creates POCO classes along with an ObjectContext class to manage them. The second, part of the EF 4.1 installation, is the ADO.NET DbContext Generator. This also creates POCO classes. But the context class that’s generated to manage the classes inherits from DbContext. So whichever workflow you begin with—Code First, Model First or Database First—you have the option to use the DbContext if that’s your preference. The DbContext has a window into the ObjectContext, so you can get there if needed.
Querying Options: LINQ to Entities or Entity SQL
Another big question developers have about the EF is if they should use LINQ to Entities or Entity SQL to write and execute queries. They also ask why the two exist. Entity SQL was built alongside the Entity Data Model as its native query syntax. LINQ is an extension of C# and Visual Basic and was created by the languages teams. When the Data Platform group learned about the work being done on LINQ, they knew it would be a natural extension to the querying needs in the EF, so they created the LINQ to Entities implementation.
LINQ to Entities as Your Default Query Strategy
LINQ to Entities is an implementation of LINQ to Objects. LINQ allows you to write queries against strongly typed objects, and in the case of the the EF, you can write queries against your entity classes. LINQ is expressed in two ways. The first is with operators. The query statements look a little like a SQL statement. The query requires an instance of an EntityContainer, which inherits from an ObjectContext, here called context:
IQueryable<Family> query = from f in context.Families where f.Pets.Any() select f;
As you type this expression, IntelliSense helps you with not only the strongly typed classes, but also with the LINQ syntax. The query returns an IQueryable of Family types. The query still needs to be executed, for example with ToList:
List<Family> reptileFamilies = query.ToList();
This causes the EF to execute a query on the database, grab the results from the database and create objects using those results.
The second way to express a LINQ query is with LINQ methods. These require lambda expressions as their parameters. I’ll compress the two previous statements into a single LINQ query:
List<Family> reptileFamiles = context.Families.Where(f=>f.Pets.Any()).ToList();
Because LINQ is so easy to use to express queries—thanks to the strong typing and IntelliSense—I generally recommend that developers plan to use LINQ as their default query strategy. You can express a broad variety of queries with LINQ. Additionally, because LINQ has many implementations, you may already have a good handle on using it. If not, you’ll most likely benefit from learning LINQ to Entities and using LINQ to Objects or one of the many other flavors of LINQ to solve other coding problems. Also, you can find a great many resources for learning how to query with LINQ.
Entity SQL for Edge Case Queries and Other Languages
Entity SQL is a string-based query syntax. To execute a query using Entity SQL, you need to use an EF ObjectQuery and pass in the Entity SQL expression. What does that look like? Here’s an example:
string eSql = "SELECT VALUE f FROM PetsModelContainer.Families AS f"; ObjectQuery<Family> query = context.CreateQuery<Family>(eSql); List<Family> families = query.ToList();
Like the IQueryable you create with LINQ, this ObjectQuery still needs to execute to retrieve the results from the database. ObjectQuery does provide an alternate way to create queries using methods that take snippets of Entity SQL as their parameters.
But with a string expression, there’s no strong typing and that query expression doesn’t get resolved until run time, which means that you won’t discover problems until then. (Note that you can use the indispensable LINQPad—found at linqpad.net—to test Entity SQL as well as LINQ to Entities, outside of Visual Studio.) So why would anyone want to use Entity SQL?
There are a number of reasons.
Let’s start with the language you code in. LINQ is part of C# and Visual Basic. There’s a power pack for F# that provides LINQ. If you code in any other .NET language, you can’t use LINQ. But you can still use Entity SQL to express queries. I’ve also found Entity SQL useful for building complex search utilities in applications. LINQ is composable, but at a certain point, it just becomes easier to simply build a string.
You can also execute queries at a lower level in the EF using connections and commands along with an Entity SQL expression. This path returns streamed data and is great for reporting or moving data around.
Query, Code Generation and Context Options
While I recommend using LINQ to Entities as your default query strategy, you’ve seen reasons why you might want to leverage Entity SQL in edge cases. This is what I do and what I recommend to clients, and I’m always happy for an excuse to exercise my infrequently used Entity SQL chops. The documentation on MSDN is pretty thorough for learning how to build Entity SQL expressions. But other than that, some old blog posts from the EF team and a chapter in my book, “Programming Entity Framework” (O’Reilly Media, 2010), I’m not aware of many resources for learning the syntax.
On the code-generation front, using EntityObjects is a fine strategy if you’re writing simple applications and want things to just work. However, if you’re architecting applications where you want to have persistence-ignorant classes, use unit testing and follow the path of separation of concerns, that’s exactly what the EF POCO support was created for. Even then, you have some flexibility in using pure objects that will require a little extra attention when coding or leveraging the proxy generation, which will let the EF do its job with little interference.
The EF 4.1 adds one more option to the code generation, which is choosing between ObjectContext or DbContext to manage your POCO classes. Many developers are jumping to the DbContext because it’s a simpler API to work with. If you need a more granular level of control over interacting with the change tracker, or prefer to leverage existing code or knowledge of the ObjectContext, you can continue to use the ObjectContext as the base for your context.
Julie Lerman is a Microsoft MVP, .NET mentor and consultant who lives in the hills of Vermont. You can find her presenting on data access and other Microsoft .NET topics at user groups and conferences around the world. She blogs at thedatafarm.com/blog and is the author of the highly acclaimed book, “Programming Entity Framework” (O’Reilly Media, 2010). Follow her on Twitter at twitter.com/julielerman.
Thanks to the following technical expert for reviewing this article: Tim Laverty