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.
DbContext API feature | Relevant EF4 feature/class | General purpose | Benefit 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. |
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.
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.
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
ObjectSet
s, which you can query
against.
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 DbSet
s 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.
public class
BreakAwayContext
: DbContext {public
DbSet
<Person
> People {get
;set
; }public
DbSet
<Destination
> Destinations {get
;set
; }public
DbSet
<Trip
> Trips {get
;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 Object
Context
.
Add
Object
, 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 Add
Object
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.
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.
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.
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.
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:
The Model project contains the domain classes, which are configured using Data Annotations.
The DataAccess project contains the
BreakAwayContext
class that
derives from DbContext
.
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.
[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.
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.
You can learn much more about Code First, its configurations, and its database interactions in Programming Entity Framework: Code First.
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:
Open your EDMX file in the Entity Data Model designer.
Right-click on the model background and select “Add Code Generation Item…” as shown in Figure 1-2.
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.
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.
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.