Chapter 1. Introducing the DbContext API

Since its first release, the most critical element in Entity Framework has been the ObjectContext. It is this class that allows us to interact with a database using a conceptual model. The context lets us express and execute queries, track changes to objects and persist those changes back to the database. The ObjectContext class interacts with other important Entity Framework classes such as the ObjectSet, which enables set operations on our entities in memory, and ObjectQuery, which is the brains behind executing queries. All of these classes are replete with features and functionality—some of it complex and much of it only necessary for special cases. After two iterations of Entity Framework (in .NET 3.5 SP1 and .NET 4) it was clear that developers were most commonly using a subset of the features, and unfortunately, some of the tasks we needed to do most frequently were difficult to discover and code.

Recognizing this, the Entity Framework team set out to make it easier for developers to access the most frequently used patterns for working with objects within Entity Framework. Their solution was a new set of classes that encapsulate this subset of ObjectContext features. These new classes use the ObjectContext behind the scenes, but developers can work with them without having to tangle with the ObjectContext unless they need to specifically use some of the more advanced features. The new set of classes was originally released as part of Entity Framework 4.1 (EF 4.1).

The prominent classes in this simplified API surface are the DbContext, DbSet, and DbQuery. This entire package of new logic is referred to as the DbContext API. The new API contains more than just the DbContext class, but it is the DbContext that orchestrates all of the new features.

The DbContext API is available in the EntityFramework.dll assembly, which also contains the logic that drives Entity Framework Code First. This assembly is separate from .NET and is even deployed separately as the EntityFramework NuGet package. A major portion of the Entity Framework is part of the .NET Framework (primarily System.Data.Entity.dll). The components that are included in .NET are considered the “core components” of Entity Framework. The DbContext API is completely dependent on these core components of Entity Framework. The Entity Framework team has indicated that they are working to move more of these core components out of .NET and into the EntityFramework.dll assembly. This will allow them to deliver more features between releases of the .NET Framework.

In Table 1-1, you can see a list of the high-level features and classes in the DbContext API, how they relate to the API surface from Entity Framework 4 (EF4), their general purpose, and their benefits.

Table 1-1. Overview of DbContext API features
DbContext API featureRelevant EF4 feature/classGeneral purposeBenefit of DbContext API

DbContext

ObjectContext

Represent a session with the database. Provide query, change tracking and save capabilities.

Exposes and simplifies most commonly used features of ObjectContext.

DbSet

ObjectSet

Provide set operations for entity types, such as Add, Attach and Remove. Inherits from DbQuery to expose query capabilities.

Exposes and simplifies most commonly used features of ObjectSet.

DbQuery

ObjectQuery

Provide querying capabilities.

The query functionality of DbQuery is exposed on DbSet, so you don’t have to interact with DbQuery directly.

Validation API

n/a

Provide automatic validation of data at the data layer. This API takes advantage of validation features already existing in .NET 4.

New to DbContext API.

Code First Model Building

n/a

Reads classes and code-based configurations to build in-memory model, metadata and relevant database.

New to DbContext API.

Getting the DbContext API into Your Project

The DbContext API is not released as part of the .NET Framework. In order to be more flexible (and frequent) with releasing new features to Code First and the DbContext API, the Entity Framework team distributes EntityFramework.dll through Microsoft’s NuGet distribution feature. NuGet allows you to add references to your .NET projects by pulling the relevant DLLs directly into your project from the Web. A Visual Studio extension called the Library Package Manager provides an easy way to pull the appropriate assembly from the Web into your projects. Figure 1-1 displays a screenshot of the Library Package Manager being used to download and add the EntityFramework NuGet package into a project.

Getting EntityFramework.dll from the Library Package Manager
Figure 1-1. Getting EntityFramework.dll from the Library Package Manager

Note

You can learn more about using NuGet and the Library Package Manager at nuget.org.

At the time of this book’s publication (early 2012), the current version of EntityFramework package is 4.3. Chapter 9 provides an overview of what to expect in future versions.

Looking at Some Highlights of the DbContext API

DbContext API is mostly targeted at simplifying your interaction with Entity Framework, both by reducing the number of methods and properties you need to wade through and by providing simpler ways to access commonly used tasks. In previous versions of Entity Framework, these tasks were often complicated to discover and code. We have a few favorites that act as great ambassadors to the new API, which we’ll share with you here. You’ll learn more about these as you work your way through the book.

Note

The samples used in this chapter are for explanation purposes only and not intended for you to perform in Visual Studio. Beginning with the next chapter, you’ll find walkthroughs that you can follow in Visual Studio.

Let’s start by looking at how the DbContext API simplifies the context that we define and work with. We’ll compare the ObjectContext and DbContext based context classes from the model we’ll be using in this book, based on BreakAway Geek Adventure’s business applications. We’ll expose queryable sets of People, Destinations, and Trips based on a Person class, a Destination class, and a Trip class.

Example 1-1 shows a subset of the BreakAwayContext class used in Entity Framework 4, based on an ObjectContext. It wraps up some known types into ObjectSets, which you can query against.

Example 1-1. BreakAwayContext that inherits from ObjectContext
public class BreakAwayContext : ObjectContext
{
  private ObjectSet<Person> _ people;
  private ObjectSet<Destination> _destinations;
  private ObjectSet<Trip> _trips;

  public ObjectSet<Person> People
  {
    get { return _people ?? (_people = CreateObjectSet<Person>("People")); }
  }

  public ObjectSet< Destination > Contacts
  {
    get { return _ destinations?? (_destinations =
              CreateObjectSet< Destination >("Destinations")); }
  }

  public ObjectSet<Trip> Trips
  {
    get { return _ trips?? (_trips = CreateObjectSet<Trip>("Trips")); }
  }
}

Example 1-2 shows the same context and sets using a DbContext and DbSets instead. Already you can see a big improvement. You can use automatic properties with DbSet (that’s the simplified get;set; pattern), something you can’t do with ObjectSet. This makes for much cleaner code right out of the gate. There is a CreateDbSet method that’s relative to CreateObjectSet, but you aren’t required to use it for the purpose of creating a DbSet when you have no other logic to apply.

Example 1-2. BreakAwayContext inheriting from DbContext
public class BreakAwayContext : DbContext
  {
    public DbSet<Person> People { get; set; }
    public DbSet<Destination> Destinations { get; set; }
    public DbSet<Trip> Trips { get; set; }
}

Reducing and Simplifying Ways to Work with a Set

In Entity Framework 4, there are a number of tasks that you can achieve from both ObjectContext and ObjectSet. For example, when adding an object instance to a set, you can use ObjectContext.AddObject or ObjectSet.AddObject. When adding an object into the context, the context needs to know which set it belongs to. With ObjectContext.AddObject, you must specify the set using a string, for example:

context.AddObject("Trips", newTrip);

When ObjectSet was introduced in Entity Framework 4, it came with its own AddObject method. This path already provides knowledge of the set so you can simply pass in the object:

context.Trips.AddObject(newTrip);

With this new method available, the only reason ObjectContext.AddObject continued to exist in Entity Framework 4 was for backward compatibility with earlier versions. But developers who were not aware of this reason were confused by the fact that there were two options.

Because the DbContext API is new, we don’t have to worry about backward compatibility, so the DbContext does not have a direct method for adding an object. Additionally, rather than providing the clunky AddObject method in DbSet, the method name is now simply Add:

context.Trips.Add(newTrip);

ObjectContext also has AttachObject and DeleteObject. DbContext does not have these methods either. DbSet has Attach and Remove, which are equivalent to ObjectSet’s Attach and Delete Object. You’ll learn more about interacting with DbSet beginning in Chapter 2.

Retrieving an Entity Using ID with DbSet.Find

One task that developers perform frequently is retrieving an entity by providing its key value. For example, you may have access to the PersonId value of a Person in a variable named _personId and would like to retrieve the relevant person data.

Typically you would construct and execute a LINQ to Entities query. Here’s a query that uses the SingleOrDefault LINQ method to filter on PersonId when executing a query on context.People:

context.People.SingleOrDefault(p => p.PersonId == _personId)

Have you written that code so often that you finally wrote a wrapper method so you could pass the key value in and it would execute the LINQ query for you? Yeah, us too. Now DbSet has that shortcut built in with the Find method, which will return an entity whose key property matches the value passed into the method:

context.People.Find(_personId)

Find has another benefit. While the SingleOrDefault query above will always query the database, Find will first check to see if that particular person is already in memory, being tracked by the context. If so, that’s what will be returned. If not, it will make the trip to the database. Under the covers, DbContext is executing logic on ObjectContext to perform the necessary tasks. You’ll learn more about DbSet.Find in Chapter 2.

Avoiding Trolling Around the Guts of Entity Framework

These are just a few examples of how much more natural it is to work with the DbContext API than the ObjectContext API. If you read Programming Entity Framework, 2e, you might be familiar with the many extension methods that Julie created and combined to simplify retrieving instances of objects that are being tracked by the context from the ObjectStateManager. One simple property, DbSet.Local, now performs that same task. In fact, thanks to the new Change Tracker API, there’s no need to dig into the ObjectStateManager. It’s not even part of the DbContext API. Instead you can use DbContext.Entry or DbContext.Entries to find and even change the information being tracked by the context. You’ll learn more about these methods in Chapter 5.

Working with the BreakAway Model

This book follows the model built around the BreakAway Geek Adventures company in the book Programming Entity Framework: Code First (O’Reilly). Even though the examples in this book use a model defined with Code First, the concepts apply just as well to a model built using the designer.

Getting the Sample Solution

If you want to follow along the book’s examples, you’ll need to download the starting solution from the download page of the book’s website at http://learnentityframework.com/downloads. In the solution you’ll find three projects:

  1. The Model project contains the domain classes, which are configured using Data Annotations.

  2. The DataAccess project contains the BreakAwayContext class that derives from DbContext.

  3. The BreakAwayConsole project is a console application where you can add and execute methods as we explore the many capabilities of the DbContext API.

When using Code First you begin with your classes. Code First uses convention to infer what the schema of the relevant database looks like and how Entity Framework can translate from your classes to that database. Code First’s conventions do not always align with your reality, however, so you can tweak how Code First maps your classes to the database by performing additional configuration. There are two ways to apply this additional configuration. One is by adding attributes to your classes and their properties (called Data Annotations) and the other is by using Code First’s Fluent API. In the Code First book, we showed you how to use both features and built up two versions of the BreakAway model—one that uses Data Annotations to configure the mappings and the other using the Fluent API.

The examples in this book and the sample download are based on the version of the model that uses Data Annotations. For example, the first class you’ll encounter in Chapter 2 is the Destination class, which is displayed here in Example 1-3.

Example 1-3. A class using Data Annotations to specify Code First configuration
[Table("Locations", Schema = "baga")]
public class Destination
{
  public Destination()
  {
    this.Lodgings = new List<Lodging>();
  }

  [Column("LocationID")]
  public int DestinationId { get; set; }
  [Required, Column("LocationName")]
  [MaxLength(200)]
  public string Name { get; set; }
  public string Country { get; set; }
  [MaxLength(500)]
  public string Description { get; set; }
  [Column(TypeName = "image")]
  public byte[] Photo { get; set; }
  public string TravelWarnings { get; set; }
  public string ClimateInfo { get; set; }

  public List<Lodging> Lodgings { get; set; }
}

The Destination class has a number of Data Annotations. It begins with a Table attribute indicating that the Destination class will map to a database table named Locations which has the schema baga. Without this annotation, Code First would presume the table name is the plural of Destination (Destinations), in the default dbo schema. The DestinationId property is configured to map to a column in the table named LocationId and the Name column to one called LocationName, with a max length of 200. The System.Data.SqlClient provider will default to specifying that the LocationName column is an nvarchar(200). Another annotation ensures that Code First understands that the Photo property maps to a column whose type is image.

The BreakAway context class inherits from System.Data.Entity.DbContext, the central class of the DbContext API. It contains properties that reflect sets of the various model classes contained in the solutions. For example a property named Destinations returns a queryable set of Destination types. The queryable set comes in the form of a DbSet class—another piece of the DbContext API. Example 1-4 gives you a sampling of properties in the BreakAwayContext class, which you’ll see more of beginning with the next chapter.

Example 1-4. A context class exposing three DbSets that wrap domain classes
  public class BreakAwayContext : DbContext
  {
    public DbSet<Destination> Destinations { get; set; }
    public DbSet<Lodging> Lodgings { get; set; }
    public DbSet<Trip> Trips { get; set; }
  }

Code First can either create a database for you or be used to map to an existing database. By default, Code First will create a database for you on your local SQL Express instance, using the namespace-qualified context name as the name for the database. For the sake of simplicity, the examples in this book will let Code First create a database automatically. After running some of the sample code, you will find a DataAccess.BreakAwayContext database on your local SQL Express instance.

Note

You can learn much more about Code First, its configurations, and its database interactions in Programming Entity Framework: Code First.

Getting DbContext from an EDMX Model

Although the book samples use Code First, you may not be using Code First to describe the model in your applications. If, instead, you are using the Entity Data Model Designer and want to take advantage of the DbContext API, there’s an easy way to do that. Visual Studio uses the Text Template Transformation Toolkit (T4) generator to generate the default ObjectContext and classes from an EDMX file. The generator uses a default template, which is designed to create class fields in a particular way. With the default template, each entity in the model becomes a class that inherits from EntityObject and a separate class is generated to manage the entities that inherits from ObjectContext.

Microsoft provides alternative templates that you can use to generate POCO classes and a DbContext-based context from the EDMX. These are available online and can easily be selected from within the Entity Data Model Designer:

  1. Open your EDMX file in the Entity Data Model designer.

  2. Right-click on the model background and select “Add Code Generation Item…” as shown in Figure 1-2.

  3. In the Add New Item window, select “Online Templates” from the left menu and then search for “DbContext.” Select the DbContext Generator template from the search results, enter a name, and click “Add” (Figure 1-3).

As a result, two templates will be added to your project. One is a context template (Model.Context.tt in the sample shown in Figure 1-4), which generates a class that inherits from DbContext, shown in Example 1-5.

Adding a new T4 template code generation item from the model’s context menu
Figure 1-2. Adding a new T4 template code generation item from the model’s context menu
Selecting the DbContext Generator template
Figure 1-3. Selecting the DbContext Generator template
Project with .tt template files and their code-generated .cs files
Figure 1-4. Project with .tt template files and their code-generated .cs files
Example 1-5. Generated BAEntities class inheriting from DbContext
public partial class BAEntities : DbContext
{
    public BAEntities()
        : base("name=BAEntities")
    {
        this.Configuration.LazyLoadingEnabled = false;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public DbSet<Activity> Activities { get; set; }
    public DbSet<Contact> Contacts { get; set; }
    public DbSet<CustomerType> CustomerTypes { get; set; }
    public DbSet<Equipment> EquipmentSet { get; set; }
    public DbSet<Trip> Trips { get; set; }
    public DbSet<Destination> Destinations { get; set; }
    public DbSet<Lodging> Lodgings { get; set; }
    public DbSet<Payment> Payments { get; set; }
}

The second template (also shown in Figure 1-4), here called Model.tt, is the one that generates POCO classes for each of the entities in your EDMX model. As you saw above, the context class exposes each of these POCO types in a DbSet.

Using this template, you can take advantage of an existing visual model and still benefit from the DbContext API, which you’ll be learning about in this book.

Ensuring DbContext Instances Get Disposed

A DbContext (and its underlying ObjectContext) are responsible for managing and tracking changes to instances of the classes in its model. These classes are also responsible for managing a connection to the database. It’s important to ensure that any resources used to perform these operations are cleaned up when the DbContext instance is no longer needed. DbContext implements the standard .NET IDisposable interface, which includes a Dispose method that will release any such resources.

The examples in this book will make use of the using pattern, which will take care of disposing the context when the using block completes (Example 1-6). If your application doesn’t make use of the using pattern, ensure that the Dispose method is called on any DbContext instances when they are no longer needed.

Example 1-6. Instantiating and disposing a context with the using pattern
public static List<Destination>  GetDestinations()
{
  using (var context = new BreakAwayContext())
  {
    var query= from d in context.Destinations
                orderby d.Name
                select d;
    return query.ToList();
  }
}

Get Programming Entity Framework: DbContext now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.