Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
407 views154 pages

Entity Framework

Download as docx, pdf, or txt
Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1/ 154

Entity Framework:

What is Entity Framework?


Writing and managing ADO.Net code for data access is a tedious and
monotonous job. Microsoft has provided an O/RM framework called "Entity
Framework" to automate database related activities for your application.
Microsoft has given the following definition of Entity Framework:
The Microsoft ADO.NET Entity Framework is an Object/Relational Mapping
(ORM) framework that enables developers to work with relational data as
domain-specific objects, eliminating the need for most of the data access
plumbing code that developers usually need to write. Using the Entity
Framework, developers issue queries using LINQ, then retrieve and
manipulate data as strongly typed objects. The Entity Framework's ORM
implementation provides services like change tracking, identity resolution,
lazy loading, and query translation so that developers can focus on their
application-specific business logic rather than the data access fundamentals.
Entity framework is an Object/Relational Mapping (O/RM) framework. It is an
enhancement to ADO.NET that gives developers an automated mechanism
for accessing & storing the data in the database.
Entity framework is useful in three scenarios. First, if you already have
existing database or you want to design your database ahead of other parts
of the application. Second, you want to focus on your domain classes and
then create the database from your domain classes. Third, you want to
design your database schema on the visual designer and then create the
database and classes.
The following figure illustrates the above scenarios.

As per the above figure, EF creates data access classes for your existing
database, so that you can use these classes to interact with the database
instead of ADO.Net directly.
EF can also create the database from your domain classes, thus you can
focus on your domain-driven design.
EF provides you a model designer where you can design your DB model and
then EF creates database and classes based on your DB model.

What is O/RM?
ORM is a tool for storing data from domain objects to relational database like
MS SQL Server, in an automated way, without much programming. O/RM
includes three main parts: Domain class objects, Relational database objects
and Mapping information on how domain objects map to relational database
objects (tables, views & storedprocedures). ORM allows us to keep our
database design separate from our domain class design. This makes the
application maintainable and extendable. It also automates standard CRUD
operation (Create, Read, Update & Delete) so that the developer doesn't
need to write it manually.

A typical ORM tool generates classes for the database interaction for your
application as shown below.

There are many ORM frameworks for .net in the market such as
DataObjects.Net, NHibernate, OpenAccess, SubSonic etc. Entity Framework
is an open source ORM framework from Microsoft.

Entity Framework Architecture


The following figure shows the overall architecture of the Entity Framework.
Let us now look at the components of the architecture individually:

EDM (Entity Data Model): EDM consists of three main parts - Conceptual
model, Mapping and Storage model.
Conceptual Model: The conceptual model contains the model classes and
their relationships. This will be independent from your database table design.
Storage Model: Storage model is the database design model which includes
tables, views, stored procedures, and their relationships and keys.
Mapping: Mapping consists of information about how the conceptual model
is mapped to the storage model.

LINQ to Entities: LINQ to Entities is a query language used to write queries


against the object model. It returns entities, which are defined in the
conceptual model. You can use your LINQ skills here.
Entity SQL: Entity SQL is another query language just like LINQ to Entities.
However, it is a little more difficult than L2E and the developer will have to
learn it separately.
Object Service:Object service is a main entry point for accessing data from
the database and to return it back. Object service is responsible for
materialization, which is the process of converting data returned from an
entity client data provider (next layer) to an entity object structure.
Entity Client Data Provider:The main responsibility of this layer is to
convert L2E or Entity SQL queries into a SQL query which is understood by
the underlying database. It communicates with the ADO.Net data provider
which in turn sends or retrieves data from the database.
ADO.Net Data Provider:This layer communicates with the database using
standard ADO.Net.

Setup Entity Framework Environment:


Entity Framework 5.0 API was distributed in two places, in NuGet package
and in .NET framework. The .NET framework 4.0/4.5 included EF core API,
whereas EntityFramework.dll via NuGet package included EF 5.0 specific
features.

This has been changed with EF 6.0 which is included in EntityFramework.dll


only and is not dependent on .NET framework.

For the basic tutorials, we will use EF 6.0, the latest version of entity
framework as of this writing.
Install the following tools to work with entity framework:

.NET Framework 4.5

Visual Studio 2012

MS SQL Server 2005/2008/2012 Express

Install EF via Nuget:


You can install entity framework into your project via nuget. Here, we will
install EF (EntityFramework.dll) via nuget in the console application in VS
2012. You can install EF via NuGet the same way in any version of
Visual Studio.
Right click on project in the solution explorer and select Manage NuGet
Packages..

This will open Manage NuGet packages dialogue box. Now, select Online in
left bar and search for EntityFramework as shown below.

This will search for all the packages related to Entity Framework. Select
EntityFramework and click on Install.

Click on the I Accept button in License Acceptance dialogue box. This will
start the installation.

After installation, make sure that the


EntityFramework.dll is included in the project.

appropriate

version

of

Now, you are ready to use Entity Framework in your project.

Setting up the database:


This tutorial will use sample SchoolDB which has different tables, stored
procedures and views. The SchoolDB database design is shown below:

You can see in the above diagram that the sample SchoolDB database
includes tables with the following relationships, for demo purpose.

One-to-One: Student and StudentAddress have a one-to-one relationship eg. Student


has zero or one StudentAddress.

One-to-Many: Standard and Teacher have a one-to-many relationship eg. many


Teachers can be associate with one Standard.

Many-to-Many: Student and Course have a many-to-many relationship using


StudentCourse table where StudentCourse table includes StudentId and CourseId. So
one student can join many courses and one course also can have many students.

Let's create first simple Entity Data Model for sample School database in the
next section.

Create Entity Data Model:

Here, we are going to create an Entity Data Model (EDM) for SchoolDB
database and understand the basic building blocks.
Entity Data Model is a model that describes entities and the relationships
between them. Let's create first simple EDM for SchoolDB database using
Visual Studio 2012 and Entity Framework 6.
1. Open Visual Studio 2012 and create a console project.

Go to PROJECT menu of visual studio -> {project name} properties - and


make sure that the project's target framework is .NET Framework 4.5, as
shown below.

2. Now, add Entity Data Model by right clicking on the project in the solution
explorer -> Add -> click New Item and select ADO.NET Entity Data Model
from popup, Give the new item the name 'School' and click Add button.

3. Entity Data Model Wizard in VS2012 opens with four options to select
from: EF Designer from database for database first approach, Empty EF
Designer
model for
model
first
approach, Empty
Code
First
model and Code First from database for Code-First approach. We will
focus on the database-first approach in the basic tutorials so select EF
Designer from database option and clickNext.

4. You can choose from your existing DB Connections or create a new


connection by clicking on the 'New Connection' button. We will use the
existing DB connection to the SchoolDB Database. This will also add a
connection string to your app.config file with the default suffix with DB name.
You can change this if you want. Click 'Next' after you set up your DB
connection.

5. In this step, you need to choose the version of Entity Framework. We will
use Entity Framework 6.0 in the basic tutorials so select Entity Framework
6.0 and click Next.

Note: If you have already installed the latest version of Entity Framework
using NuGet manager as shown in the Setup Environment section then this

step of the wizard will no longer appear since you have already installed
Entity Framework.
6. This step will display all the Tables, Views and Stored Procedures (SP) in
the database. Select the Tables, Views and SPs you want, keep the default
checkboxes selected and click Finish. You can change Model Namespace if
you want.

Note:

Pluralize or singularize generated object names checkbox singularizes


an entityset name, if the table name in the database is plural. For example, if
SchoolDB has Students table name then entityset would be singular Student.
Similarly, relationships between the models will be pluralized if the table has
one-to-many or many-to-many relationship with other tables. For example,
Student has many-to-many relationship with Course table so Student entity
set will have plural property name 'Courses' for the collection of courses.

The second checkbox, Include foreign key columns in the model,


includes foreign key property explicitly to represent the foreign key. For
example, Student table has one-to-many relationship with Standard table. So
every student is associated with only one standard. To represent this in the
model, Student entityset includes StandardId property with Standard
navigation property. If this checkbox is unchecked then it will only include
the Standard property, but not the StandardId in the Student entityset.
The third checkbox, Import selected stored procedures and functions
into entity model, automatically creates Function Imports for the stored
procedures and functions. You don't need to manually import this, as was
necessary prior to Entity Framework 5.0.
7. After clicking on 'Finish', a School.edmx file will be added into your
project.
Open EDM designer by double clicking on School.edmx. This displays all the
entities for selected tables and the relationships between them as shown
below:

EDM also adds a connection string in the config file as shown below.

<?xml version="1.0"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit
http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework"
type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection,
EntityFramework, Version=6.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
</configSections>
<startup>
<supportedRuntime version="v4.0"
sku=".NETFramework,Version=v4.5"/>
</startup>
<entityFramework>
<defaultConnectionFactory
type="System.Data.Entity.Infrastructure.SqlConnectionFactory,
EntityFramework"/>
<providers>
<provider invariantName="System.Data.SqlClient"
type="System.Data.Entity.SqlServer.SqlProviderServices,
EntityFramework.SqlServer"/>
</providers>
</entityFramework>
<connectionStrings>
<add name="SchoolDBEntities"
connectionString="metadata=res://*/SchoolDB.csdl|
res://*/SchoolDB.ssdl|
res://*/SchoolDB.msl;provider=System.Data.SqlClient;provider
connection string=&quot;data source=.\sqlexpress;initial
catalog=SchoolDB;integrated
security=True;multipleactiveresultsets=True;application
name=EntityFramework&quot;"
providerName="System.Data.EntityClient"/>
</connectionStrings>
</configuration>

In this way, you can create a simple EDM from your existing database.

Now, let's examine all the building blocks of generated EDM (School.edmx)
as shown in the above figure.

Entity-Table Mapping:
Each entity in EDM is mapped with the database table. You can check the
entity-table mapping by right clicking on any entity in the EDM designer ->
select Table Mapping. Also, if you change any property name of the entity
from designer then the table mapping would reflect that change
automatically.

Context & Entity Classes:


Every Entity Data Model generates one context class and entity class for each
DB table included in the EDM. Expand School.edmx and see two important
files, {EDM Name}.Context.tt and {EDM Name}.tt:

School.Context.tt: This T4 template file generates a context class whenever


you change Entity Data Model (.edmx file). You can see the context class file
by expanding School.Context.tt. The context class resides in {EDM
Name}.context.cs file. The default context class name is {DB Name} +
Entities. For example, the context class name for SchoolDB is
SchoolDBEntities, then the context class is derived from DBContext class in
Entity Framework. (Prior to EF 5.0 it had been derived from ObjectContext.)

School.tt: School.tt is a T4 template file that generates entity classes for


each DB table. Entity classes are POCO (Plain Old CLR Object) classes. The
following code snippet shows the Student entity.

public partial class Student


{
public Student()
{
this.Courses = new HashSet<Course>();
}
public int StudentID { get; set; }
public string StudentName { get; set; }
public Nullable<int> StandardId { get; set; }
public byte[] RowVersion { get; set; }

public virtual Standard Standard { get; set; }


public virtual StudentAddress StudentAddress { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}

EDM Designer: EDM designer represents your conceptual model. It consists


of Entities, and associations & multiplicity between the entities. Initially, it
will look exactly like your database table structure but you can add, merge or
remove columns, which are not required by your application from this
designer. You can even add a new object in this model, which can have
columns from different database tables from context menu, as shown in the
figure above. Remember, whatever changes done here should be mapped
with the storage model. So you have to be careful, while making any changes
in the designer.
You can open this EDM designer in XML view where you can see all the three
parts of the EDM - Conceptual schema (CSDL), Storage schema (SSDL) and
mapping schema (MSL), together in XML view.
Right click on School.edmx -> click 'Open with..', this will open a popup
window.

Select 'XML (text) Editor' in the popup window.

Visual Studio cannot display the model in Design view and in XML format at
the same time, so you will see a message asking whether its OK to close the
Design view of the model. Click Yes. This will open the XML format view. You
can see the following XML view by toggling all outlining as shown below.

You can see SSDL content, CSDL content and C-S mapping content here. If
you expand SSDL and CSDL, each one has some common XML node under
each schema node. You don't need to edit the xml data because this can be
accomplished easier in the Model Browser.

Model Browser:

We have created our first Entity Data Model for School database in the
previous section. The visual designer of EDM does not display all the objects
it creats. It only display entities which are mapped to the database tables
and views.
Model Browser gives you all the information about all the objects and
functions EDM has created. Open Model Browser by right clicking on the EDM
Designer and select Model Browser from the context menu.
Model browser contains all the information about the EDM, its conceptual
model, storage model and mapping information as shown below.

As you can see in the above figure, model browser contains the following
objects:
Diagrams: Model browser contains visual diagrams of EDM. We have seen a
default visual diagram created by EDM. You can also create multiple
diagrams for one EDM if your application has a large number of entities.

Entity Types: Entity types lists all the class types which are mapped to the
database tables.
Complex Types: Complex types are the classes which are generated by
EDM to contain the result of stored procedures, table-valued function etc.
These complex types are customized classes for different purposes.
Enum Types: Enum types lists all the entities which are used as Enum in
entity framework.
Associations: Associations lists all foreign key relationship between the
entity types.
Function Imports: Function imports lists all the functions which will be
mapped to stored procedures, table-valued functions, etc. Stored procedures
and table-valued functions will be used as functions and not an entity in EF.
.Store: Store represents database schema (SSDL).

DBContext:
As you have seen in the previous Create Entity Data Model section, EDM
generates the SchoolDBEntities class, which was
derived from
the System.Data.Entity.DbContext class, as shown below. The class that
derives DbContext is called context class in entity framework.

Prior to EntityFramework 4.1, EDM used to generate context classes that


were derived from the ObjectContext class. It was a little tricky to work with
ObjectContext. DbContext is conceptually similar to ObjectContext. It is a
wrapper around ObjectContext which is useful in all the development models:
Code First, Model First and Database First.
DbContext is an important part of Entity Framework. It is a bridge between
your domain or entity classes and the database.

DbContext is the primary class that is responsible for interacting with data as
object. DbContext is responsible for the following activities:

EntitySet: DbContext contains entity set (DbSet<TEntity>) for all the entities which is
mapped to DB tables.

Querying: DbContext converts LINQ-to-Entities queries to SQL query and send it to the
database.

Change Tracking: It keeps track of changes that occurred in the entities after it has been
querying from the database.

Persisting Data: It also performs the Insert, Update and Delete operations to the
database, based on what the entity states.

Caching: DbContext does first level caching by default. It stores the entities which have
been retrieved during the life time of a context class.

Manage Relationship: DbContext also manages relationship using CSDL, MSL and
SSDL in DB-First or Model-First approach or using fluent API in Code-First approach.

Object Materialization: DbContext converts raw table data into entity objects.

The following is an example of SchoolDBEntities class (context class that


derives DbContext) generated with EDM for SchoolDB database in the
previous section.

namespace EFTutorials
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Core.Objects;
using System.Linq;
public partial class SchoolDBEntities : DbContext
{
public SchoolDBEntities()
: base("name=SchoolDBEntities")
{
}

protected override void OnModelCreating(DbModelBuilder


modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Standard> Standards { get; set; }
public virtual DbSet<Student> Students { get; set; }
public virtual DbSet<StudentAddress> StudentAddresses { get;
set; }
public virtual DbSet<Teacher> Teachers { get; set; }
public virtual DbSet<View_StudentCourse> View_StudentCourse {
get; set; }
public virtual ObjectResult<GetCoursesByStudentId_Result>
GetCoursesByStudentId(Nullable<int> studentId)
{
var studentIdParameter = studentId.HasValue ?
new ObjectParameter("StudentId", studentId) :
new ObjectParameter("StudentId", typeof(int));
return
((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<GetCourses
ByStudentId_Result>("GetCoursesByStudentId", studentIdParameter);
}
public virtual int sp_DeleteStudent(Nullable<int> studentId)
{
var studentIdParameter = studentId.HasValue ?
new ObjectParameter("StudentId", studentId) :
new ObjectParameter("StudentId", typeof(int));

return
((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("sp_DeleteS
tudent", studentIdParameter);
}
public virtual ObjectResult<Nullable<decimal>>
sp_InsertStudentInfo(Nullable<int> standardId, string studentName)
{
var standardIdParameter = standardId.HasValue ?
new ObjectParameter("StandardId", standardId) :
new ("StandardId", typeof(int));
var studentNameParameter = studentName != null ?
new ObjectParameter("StudentName", studentName) :
new ObjectParameter("StudentName", typeof(string));
return
((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Nullable<d
ecimal>>("sp_InsertStudentInfo", standardIdParameter,
studentNameParameter);
}
public virtual int sp_UpdateStudent(Nullable<int> studentId,
Nullable<int> standardId, string studentName)
{
var studentIdParameter = studentId.HasValue ?
new ObjectParameter("StudentId", studentId) :
new ObjectParameter("StudentId", typeof(int));
var standardIdParameter = standardId.HasValue ?
new ObjectParameter("StandardId", standardId) :
new ObjectParameter("StandardId", typeof(int));
var studentNameParameter = studentName != null ?
new ObjectParameter("StudentName", studentName) :

new ObjectParameter("StudentName", typeof(string));


return
((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("sp_Update
Student", studentIdParameter, standardIdParameter,
studentNameParameter);
}
}
}
As you can see in the above example, context class (SchoolDBEntities)
includes entity set of type DbSet<TEntity> for all the entities. Learn more
about DbSet class here. It also includes functions for the stored procedures
and views included in EDM.
Context class overrides OnModelCreating method. Parameter DbModelBuilder
is called Fluent API, which can be used to configure entities in the Code-First
approach.

Instantiating DbContext:
You can use DbContext by instantiating context class and use for CRUD
operation as shown below.

using (var ctx = new SchoolDBEntities())


{
//Can perform CRUD operation using ctx here..
}

Getting ObjectContext from DbContext:


DBContext API is easier to use than ObjectContext API for all common tasks.
However, you can get the reference of ObjectContext from DBContext in
order to use some of the features of ObjectContext. This can be done by
using IObjectContextAdpter as shown below:

using (var ctx = new SchoolDBEntities())


{
var objectContext = (ctx as
System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext;
//use objectContext here..
}

EDM also generates entity classes.

Types of Entity in Entity Framework:


We created EDM for existing database in the previous section. As you have
learned in the previous section that EDM contains entities for each table in
the database. There are two types of Entities in Entity Framework 5.0/6.0:
POCO entity and dynamic proxy entity.

POCO Entity (Plain Old CLR Object):


POCO class is the class that doesn't depend on any framework specific base
class. It is like any other normal .net class which is why it is called "Plain Old
CLR Objects".
These POCO entities (also known as persistence-ignorant objects) support
most of the same query, insert, update, and delete behaviors as entity types
that are generated by the Entity Data Model. The following is an example of
Student POCO entity.

public class Student


{
public Student()
{
this.Courses = new List<Course>();
}

public int StudentID { get; set; }


public string StudentName { get; set; }
public Nullable<int> StandardId { get; set; }
public Standard Standard { get; set; }
public StudentAddress StudentAddress { get; set; }
public IList<Course> Courses { get; set; }
}

Dynamic Proxy (POCO Proxy):


Dynamic Proxy is a runtime proxy class of POCO entity. It is like a wrapper
class
of
POCO
entity.
Dynamic
proxy
entities
allow lazy
loading and automatic change tracking.
POCO entity should meet the following requirements to become a POCO
proxy:
1. A POCO class must be declared with public access.
2. A POCO class must not be sealed (NotInheritable in Visual Basic)
3. A POCO class must not be abstract (MustInherit in Visual Basic).
4. Each navigation property must be declared as public, virtual
5. Each collection property must be ICollection<T>
6. ProxyCreationEnabled option must NOT be false (default is true) in
context class
The following Student POCO entity meets all of the above requirement to
become dynamic proxy entity at runtime.

public class Student


{
public Student()
{

this.Courses = new HashSet<Course>();


}
public int StudentID { get; set; }
public string StudentName { get; set; }
public Nullable<int> StandardId { get; set; }
public virtual Standard Standard { get; set; }
public virtual StudentAddress StudentAddress { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}

Note: By default dynamic proxy is enabled for every entity. However, you
can disable dynamic proxy by setting the ProxyCreationEnabled option to
false in context class.
context.Configuration.ProxyCreationEnabled = false;

EDM generates POCO entities which satisfy the above requirements for a
dynamic proxy by default.
At
runtime,
type
of
Student
System.Data.Entity.DynamicProxies.Student as below:

will

be

Getting the actual entity type from a dynamic


proxy:
You can use ObjectContext.GetObjectType() to find the actual type of
dynamic proxy as shown below:

Entity can have two types of properties, Scalar and Navigation properties.

Scalar properties:
Scalar properties are properties whose actual values are contained in the
entity. For example, Student entity has scalar properties like StudentId and
StudentName. These correspond with the Student table columns.

Navigation properties:
Navigation properties are pointers to other related entities. The Student has
Standard property as a navigation property that will enable the application to
navigate from a Student to related Standard entity.

Entity Relationships:
Here, you will learn how entity framework manages the relationships
between entities.
Entity framework supports three types of relationships, same as database: 1)
One to One 2) One to Many, and 3) Many to Many.
We have created an Entity Data Model for the SchoolDB database in
the Create Entity Data Modelsection. The following figure shows the visual
designer for that EDM with all the entities and relationships among them.

Let's see how each relation (association) is being managed by entity


framework.

One-to-One Relationship:
As you can see in the above figure, Student and StudentAddress have a Oneto-One relationship (zero or one). A student can have only one or zero
address. Entity framework adds Student navigation property into
StudentAddress entity and StudentAddress navigation entity into Student
entity. Also, StudentAddress entity has StudentId property as PrimaryKey
which makes it a One-to-One relationship.
The following code snippet shows Student and StudentAddress entity classes.

public partial class Student


{
public Student()

{
this.Courses = new HashSet<Course>();
}
public int StudentID { get; set; }
public string StudentName { get; set; }
public Nullable<int> StandardId { get; set; }
public byte[] RowVersion { get; set; }
public virtual Standard Standard { get; set; }
public virtual StudentAddress StudentAddress { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
public partial class StudentAddress
{
public int StudentID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public virtual Student Student { get; set; }
}

As you can see in the above code, Student entity class includes
StudentAddress navigation property and StudentAddress includes Student
navigation property with foreign key property StudentId. This way EF handles
one-to-one relationship between entities.

One-to-Many Relationship:
The Standard and Teacher entities have a One-to-Many relationship marked
by multiplicity where 1 is for One and * is for many. This means that

Standard can have many Teachers whereas Teacher can associate with only
one Standard.
To represent this, The Standard entity has the collection navigation
property Teachers (please notice that it's plural), which indicates that one
Standard can have a collection of Teachers (many teachers). And Teacher
entity has a Standard navigation property (Not a Collection) which indicates
that Teacher is associated with one Standard. Also, it contains StandardId
foreign key (StandardId is a PK in Standard entity). This makes it One-toMany relationship.
The following code snippet shows Standard and Teacher entity class created
by EDM.

public partial class Standard


{
public Standard()
{
this.Students = new HashSet<Student>();
this.Teachers = new HashSet<Teacher>();
}
public int StandardId { get; set; }
public string StandardName { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students { get; set; }
public virtual ICollection<Teacher> Teachers { get; set; }
}
public partial class Teacher
{
public Teacher()
{
this.Courses = new HashSet<Course>();

}
public int TeacherId { get; set; }
public string TeacherName { get; set; }
public Nullable<int> StandardId { get; set; }
public Nullable<int> TeacherType { get; set; }
public virtual ICollection<Course> Courses { get; set; }
public virtual Standard Standard { get; set; }
}

As you can see in the above code snippet, Standard entity class has Teachers
property of type ICollection, so that it can contain multiple Teacher objects.
(It initializes Teachers property with HashSet<Teacher> in the constructor, so
that you can add Teacher objects into collection without worrying about
initializing it.)
Also, Teacher entity class includes Standard property with StandardId for
foreign key property. Entity framework includes this foreign key property
because we checked Include foreign key columns in the model in the
EDM wizard while creating EDM in the Create Entity Data Model section.

Many-to-Many Relationship:
Student and Course have Many-to-Many relationships marked by *
multiplicity. It means one Student can enrol for many Courses and also, one
Course can be be taught to many Students.
The database design includes StudentCourse joining table which includes the
primary key of both the tables (Student and Course table). Entity Framework
represents many-to-many relationships by not having entityset for the
joining table in CSDL, instead it manages this through mapping.
As you can see in the above figure, Student entity includes Courses property
and Course entity includes Students property to represent many-to-many
relationship between them.

The following code snippet shows Student and Course entity classes.

public partial class Student


{
public Student()
{
this.Courses = new HashSet<Course>();
}
public int StudentID { get; set; }
public string StudentName { get; set; }
public Nullable<int> StandardId { get; set; }
public byte[] RowVersion { get; set; }
public virtual Standard Standard { get; set; }
public virtual StudentAddress StudentAddress { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
public partial class Course
{
public Course()
{
this.Students = new HashSet<Student>();
}
public int CourseId { get; set; }
public string CourseName { get; set; }
public System.Data.Entity.Spatial.DbGeography Location { get; set; }
public Nullable<int> TeacherId { get; set; }
public virtual Teacher Teacher { get; set; }

public virtual ICollection<Student> Students { get; set; }


}

Note: Entity framework supports many-to-many relationship only when the


joining table (StudentCourse in this case) does NOT include any columns
other than PKs of both the tables. If the join tables contain additional
columns, such as DateCreated, then the EDM creates entity for middle table
as well and you will have to manage CRUD operation for many-to-many
entities manually.
Open EDM in XML view. You can see that SSDL has StudentCourse entityset,
but CSDL doesn't have StudentCourse entityset. Instead, it's being mapped
in the navigation property of the Student and Course entity. In MSL (C-S
Mapping), it has mapping between Student and Course put into the
StudentCourse table in <AssociationSetMapping/>

Thus, Many-to-Many relationship is being managed by C-S mapping in EDM.


So when you add a Student in a Course or a Course in a Student entity and
when you save it, it will then insert PK of the added student and course in
StudentCourse table. So this mapping not only enables a convenient
association directly between the two entities, but also manages querying,
inserts, and updates across this joint.

Entity Graph:
When an entity has a relationship with other entities, then the full object
hierarchy is called an 'entity graph'. For example the following is a Student
entity graph, that includes hierarchy of Student entity with Standard,
StudentAddress & Course entities.

Learn about the lifecycle of these entities in the next section.

Entity Lifecycle:
Before we work on CRUD operation (Create, Read, Update, Delete), it's
important to understand the entity lifecycle and how it is being managed by
the EntityFramework.
During an entity's lifetime, each entity has an entity state based on the
operation performed on it via the context (DbContext). The entity state is an
enum of type System.Data.Entity.EntityState that includes the following
values:
1. Added
2. Deleted
3. Modified
4. Unchanged
5. Detached
The Context not only holds the reference to all the objects retrieved from the
database but also it holds the entity states and maintains modifications made
to the properties of the entity. This feature is known as Change Tracking.

The change in entity state from the Unchanged to the Modified state is the
only state that's automatically handled by the context. All other changes
must be made explicitly using proper methods of DbContext and DbSet.
The following figure illustrates how the operation performed on entity
changes its' states which, in turn, affects database operation.

As you can see in the above figure, new entity in context has Added entity
state. So the context will execute insert command to the database. In the
same way, when you retrieve an existing entity using L2E queries, it will have
Unchanged state, this is because you have just retrieved an entity and hasn't
performed any operation on it yet. When you modify values of existing entity,
it changes its state to Modified which in turn will execute update command
on SaveChanges. Deleted entity from context will have Deleted state which in
turn will execute delete command to the database.
So, in this way, operations performed on entities changes states. Context
builds and executes database commands based on the state of an entity.

Code First development with Entity


Framework:

Entity Framework supports three different development approaches to use


entity framework in your application.
1. Code First
2. Model First
3. Database first

Code First:
In the Code First approach, you avoid working with visual model designer
(EDMX) completely. You write your POCO classes first and then create
database from these POCO classes.
Developers who follow the path of Domain-Driven Design (DDD) principles,
prefer to begin by coding their domain classes first and then generating the
database required to persist their data.

Model First development with Entity


Framework:
In the Model First approach, you create Entities, relationships, and
inheritance hierarchies directly on the design surface of EDMX and then
generate database from your model.
So, in the Model First approach, add new ADO.NET Entity Data Model and
select Empty EF Designer model in Entity Data Model Wizard.

You can create an entity, association and inheritance on an empty designer


by right clicking on designer surface -> Add New -> Entity.

In the Add Entity dialogue, enter name of the entity. Also you can change the
default settings for Entity set and key property. We will keep the default
settings as it is. Click OK to generate an entity.

You can also add properties in the generated entity by right clicking on entity
- > Add New -> Scalar property.

Enter the name of scalar property as shown below.

In the same way, you can add other entities and associations using toolbox.

After creating the required entities, associations, and inheritance on the


design surface of the empty model, you can use the designer's context menu
option 'Generate database from model' to generate DDL script.

This will open Generate Database Wizard. You can select existing database
or create a new connection by clicking on New Connection.. Select
database server and enter the name of the database to create and then click
OK. It will ask you for the confirmation for creating a new database.
Click Yes to create a database.

Click Next to generate DDL for the DB model as shown below.

This will add ModelName.edmx.sql file in the project. You can execute DDL
scripts in Visual Studio by opening .sql file -> right click -> Execute.
Now, you can generate context class and entities by right clicking on the
designer and selecting Add Code Generation Item..

This will add (ModelName).Context.tt and (ModelName).tt with context class


and entity classes as shown below.

So, in this way, you can design your DB model and then generate a database
and classes based on the model. This is called the Model-First approach.

Database First development with Entity


Framework:
We have seen this approach in Create Entity Data Model where we created
the EDM, context and entity classes from an existing database. So, when you
generate EDMX from an existing database then it is a Database First
approach.

Entity Data Model can be updated whenever database schema changes. Also,
database-first approach supports stored procedure, view, etc.
These basic tutorials cover the Database-first approach.

Learn how to choose appropriate EF development approach in the next


chapter.

Choose development approach with


Entity Framework:
We have seen Code-first, Model-first and Database-first approaches in the
previous sections. So, now you have to make a decision about which
development approach to use in your application. The following figure
illustrates the decision tree.

As per the above figure, if you already have an existing application with
domain classes, then you can use the code-first approach because you can
create a database from your existing classes in this approach. If you have an
existing database, then you can create an EDM from an existing database in
the database-first approach. If you do not have an existing database or

domain classes, and you prefer to design your DB model on the visual
designer, then go for Model-first approach.

Querying with EDM:


We have created EDM, DbContext, and entity classes in the previous
sections. Here, you will learn the different types of queries an entity
framework supports, which is in turn converted into SQL query for the
underlaying database.
Entity framework supports three types of queries: 1) LINQ to Entities, 2)
Entity SQL, and 3) Native SQL

LINQ to Entities:
Language-Integrated Query (LINQ) is a powerful query language introduced
in Visual Studio 2008. You can use LINQ in C# or Visual Basic to query
different data sources. LINQ-to-Entities operates on entity framework entities
to access the data from the underlying database. You can use LINQ method
syntax or query syntax when querying with EDM. Visit LINQ Tutorials to learn
LINQ step-by-step.
LINQ Method syntax:

//Querying with LINQ to Entities


using (var context = new SchoolDBEntities())
{
var L2EQuery = context.Students.where(s => s.StudentName ==
"Bill");
var student = L2EQuery.FirstOrDefault<Student>();
}

LINQ Query syntax:

using (var context = new SchoolDBEntities())


{
var L2EQuery = from st in context.Students
where st.StudentName == "Bill"
select st;
var student = L2EQuery.FirstOrDefault<Student>();
}
First, you have to create an object of context class, which is
SchoolDBEntities. You should initialize it in using() so that once it goes out of
scope then it will automatically call Dispose() method of DbContext. In both
the syntaxes above, context returns IQueryable.
Learn different types of LINQ to Entities projection query in the Projection
Query section.

Entity SQL:
Entity SQL is another way to create a query. It is processed by the Entity
Frameworks Object Services directly. It returns ObjectQuery instead of
IQueryable.
You need ObjectContext to create a query using Entity SQL.
The following code snippet shows the same query result as L2E query above.

//Querying with Object Services and Entity SQL


string sqlString = "SELECT VALUE st FROM SchoolDBEntities.Students " +
"AS st WHERE st.StudentName == 'Bill'";
var objctx = (ctx as IObjectContextAdapter).ObjectContext;
ObjectQuery<Student> student =
objctx.CreateQuery<Student>(sqlString);
Student newStudent = student.First<Student>();

You can also use EntityConnection and EntityCommand to execute Entity SQL
as shown below:

using (var con = new EntityConnection("name=SchoolDBEntities"))


{
con.Open();
EntityCommand cmd = con.CreateCommand();
cmd.CommandText = "SELECT VALUE st FROM
SchoolDBEntities.Students as st where st.StudentName='Bill'";
Dictionary<int, string> dict = new Dictionary<int, string>();
using (EntityDataReader rdr =
cmd.ExecuteReader(CommandBehavior.SequentialAccess |
CommandBehavior.CloseConnection))
{
while (rdr.Read())
{
int a = rdr.GetInt32(0);
var b = rdr.GetString(1);
dict.Add(a, b);
}
}
}
EntityDataReader doesn't return ObjectQuery. Instead, it returns the data in
rows & columns.
Visit MSDN blog to learn Entity SQL.

Native SQL:
You can execute native SQL queries for a relational database as shown
below:

using (var ctx = new SchoolDBEntities())


{

var studentName = ctx.Students.SqlQuery("Select studentid,


studentname, standardId from Student where
studentname='Bill'").FirstOrDefault<Student>();
}

Linq-to-Entities Projection Queries:


Here, you will learn how to write LINQ-to-Entities queries and get the result
entities. Visit LINQ Tutorials to learn LINQ step by step.
Projection is a process of selecting data in a different shape rather than a
specific entity being queried. There are many ways of projection. We will now
see some projection styling:

First/FirstOrDefault:
If you want to get a single student object, when there are many students,
whose name is "Student1" in the database, then use First or FirstOrDefault,
as shown below:

using (var ctx = new SchoolDBEntities())


{
var student = (from s in ctx.Students
where s.StudentName == "Student1"
select s).FirstOrDefault<Student>();
}

The above query will result in the following database query:

SELECT TOP (1)


[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 'Student1' = [Extent1].[StudentName]

The difference between First and FirstOrDefault is that First() will throw an
exception if there is no result data for the supplied criteria whereas
FirstOrDefault() returns default value (null) if there is no result data.

Single/SingleOrDefault:
You can also use Single or SingleOrDefault to get a single student object as
shown below:

using (var ctx = new SchoolDBEntities())


{
var student = (from s in context.Students
where s.StudentID == 1
select s).SingleOrDefault<Student>();
}
The above query would execute the following database query:

SELECT TOP (2)


[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 1 = [Extent1].[StudentID]
go
Single or SingleOrDefault will throw an exception, if the result contains more
than one element. Use Single or SingleOrDefault where you are sure that the
result would contain only one element. If the result has multiple elements
then there must be some problem.

ToList:
If you want to list all the students whose name is 'Student1' (provided there
are many students has same name) then use ToList():

using (var ctx = new SchoolDBEntities())

{
var studentList = (from s in ctx.Students
where s.StudentName == "Student1"
select s).ToList<Student>();
}

The above query would result in the following database query:

SELECT
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 'Student1' = [Extent1].[StudentName]
go

GroupBy:
If you want to group students by standardId, then use groupby:

using (var ctx = new SchoolDBEntities())


{
var students = from s in ctx.Students
groupby s.StandardId into studentsByStandard
select studentsByStandard;
}

The above query would execute the following database query:

SELECT
[Project2].[C1] AS [C1],
[Project2].[StandardId] AS [StandardId],
[Project2].[C2] AS [C2],

[Project2].[StudentID] AS [StudentID],
[Project2].[StudentName] AS [StudentName],
[Project2].[StandardId1] AS [StandardId1]
FROM ( SELECT
[Distinct1].[StandardId] AS [StandardId],
1 AS [C1],
[Extent2].[StudentID] AS [StudentID],
[Extent2].[StudentName] AS [StudentName],
[Extent2].[StandardId] AS [StandardId1],
CASE WHEN ([Extent2].[StudentID] IS NULL) THEN CAST(NULL AS int)
ELSE 1 END AS [C2]
FROM (SELECT DISTINCT
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1] ) AS [Distinct1]
LEFT OUTER JOIN [dbo].[Student] AS [Extent2] ON ([Distinct1].
[StandardId] = [Extent2].[StandardId]) OR (([Distinct1].[StandardId] IS
NULL) AND ([Extent2].[StandardId] IS NULL))
) AS [Project2]
ORDER BY [Project2].[StandardId] ASC, [Project2].[C2] ASC
go

OrderBy:
If you want to get the list of students sorted by StudentName, then use
OrderBy:

using (var ctx = new SchoolDBEntities())


{
var student1 = from s in ctx.Students
orderby s.StudentName ascending
select s;
}

The above query would execute the following database query:

SELECT
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
ORDER BY [Extent1].[StudentName] ASC
go

Anonymous Class result:


If you want to get only StudentName, StandardName and list of Courses for
that student in a single object, then write the following projection:

using (var ctx = new SchoolDBEntities())


{
var projectionResult = from s in ctx.Students
where s.StudentName == "Student1"
select new {
s.StudentName, s.Standard.StandardName, s.Courses
};
}

The above query would execute the following database query:

SELECT
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent2].[City] AS [City]
FROM [dbo].[Student] AS [Extent1]
LEFT OUTER JOIN [dbo].[StudentAddress] AS [Extent2] ON [Extent1].
[StudentID] = [Extent2].[StudentID]
WHERE 1 = [Extent1].[StandardId]
go

The projectionResult in the above query will be the anonymous type, because
there is no class/entity which has these properties. So, the compiler will
mark it as anonymous.

Nested queries:
You can also execute nested LINQ to entity queries as shown below:

The nested query shown above will result in an anonymous list with a
StudentName and Course object.

SELECT
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Join1].[CourseId1] AS [CourseId],
[Join1].[CourseName] AS [CourseName],
[Join1].[Location] AS [Location],
[Join1].[TeacherId] AS [TeacherId]
FROM [dbo].[Student] AS [Extent1]
INNER JOIN (SELECT [Extent2].[StudentId] AS [StudentId], [Extent3].
[CourseId] AS [CourseId1], [Extent3].[CourseName] AS [CourseName],
[Extent3].[Location] AS [Location], [Extent3].[TeacherId] AS [TeacherId]
FROM [dbo].[StudentCourse] AS [Extent2]
INNER JOIN [dbo].[Course] AS [Extent3] ON [Extent3].[CourseId] =
[Extent2].[CourseId] ) AS [Join1] ON [Extent1].[StudentID] = [Join1].
[StudentId]
WHERE 1 = [Extent1].[StandardId]
go

In this way, you can do a projection of the result, in the way that you would
like the data to be.

DBSet Class
DBSet class represents an entity set that is used for create, read, update,
and delete operations. A generic version of DBSet (DbSet<TEntity>) can be
used when the type of entity is not known at build time.
You can get the reference of DBSet by using DBContext, eg.
dbcontext.Students, dbcontext.Standards, or any other entity set. DbContext
class includes DbSet as shown below:

Some of the important methods of DBSet class are shown in the table
below::

Method Name

Return Type

Description

Add

Added entity
type

Adds the given entity to the context the Added state. When
changes are being saved, the entities in the Added states a
inserted into the database. After the changes are saved, th
object state changes to Unchanged.
Example:
dbcontext.Students.Add(studentEntity)

AsNoTracking<En DBQuery<Enti Returns a new query where the entities returned will not be
tity>
ty>
cached in the DbContext. (Inherited from DbQuery.)

Entities returned as AsNoTracking, will not be tracke


DBContext. This will be significant performance boos
read only entities.

Example:
var studentList =
dbcontext.Students.AsNoTracking<Student>().ToList<Stude
;
Attach(Entity)

Entity which
Attaches the given entity to the context in the Unchanged s
was passed as
parameter
Example:
dbcontext.Students.Attach(studentEntity);

Create

Entity

Creates a new instance of an entity for the type of this set.


instance is not added or attached to the set. The instance
returned will be a proxy if the underlying context is configu
create proxies and the entity type meets the requirements
creating a proxy.
Example:
var newStudentEntity = dbcontext.Students.Create();

Find(int)

Entity type

Uses the primary key value to attempt to find an entity trac


by the context. If the entity is not in the context then a que
be executed and evaluated against the data in the data sou
and null is returned if the entity is not found in the context
the data source. Note that the Find also returns entities tha
been added to the context but have not yet been saved to
database.

Method Name

Return Type

Description

Example:
Student studEntity = dbcontext.Students.Find(1);
Include

DBQuery

Returns the included non generic LINQ to Entities query aga


DbContext. (Inherited from DbQuery)

Example:
var studentList =
dbcontext.Students.Include("StudentAddress").ToList<Stud
;
var studentList = dbcontext.Students.Include(s =>
s.StudentAddress).ToList<Student>();
Remove

Removed
entity

Marks the given entity as Deleted. When the changes are s


the entity is deleted from the database. The entity must ex
the context in some other state before this method is called
Example:
dbcontext.Students.Remove(studentEntity);

SqlQuery

DBSqlQuery

Creates a raw SQL query that will return entities in this set.
default, the entities returned are tracked by the context; th
be changed by calling AsNoTracking on theDbSqlQuery<TE
returned from this method.
Example:
var studentEntity = dbcontext.Students.SqlQuery("select *
student where studentid = 1").FirstOrDefault<Student>();

DBEntityEntry Class
DBEntityEntry is an important class, which is useful in retrieving various
information about an entity. You can get an instance of DBEntityEntry of a
particular entity by using Entry method of DBContext. For example:
DBEntityEntry studentEntry = dbcontext.Entry(StudentEntity);

DBEntityEntry enables you to access entity state, current, and original values
of all the property of a given entity. The following example code shows how
to retrieve important information of a particular entity.

using (var dbCtx = new SchoolDBEntities())


{
//get student whose StudentId is 1
var student = dbCtx.Students.Find(1);
//edit student name
student.StudentName = "Edited name";
//get DbEntityEntry object for student entity object
var entry = dbCtx.Entry(student);
//get entity information e.g. full name
Console.WriteLine("Entity Name: {0}", entry.Entity.GetType().FullName);
//get current EntityState
Console.WriteLine("Entity State: {0}", entry.State );
Console.WriteLine("********Property Values********");
foreach (var propertyName in entry.CurrentValues.PropertyNames )
{
Console.WriteLine("Property Name: {0}", propertyName);
//get original value
var orgVal = entry.OriginalValues[propertyName];
Console.WriteLine("

Original Value: {0}", orgVal);

//get current values


var curVal = entry.CurrentValues[propertyName];

Console.WriteLine("

Current Value: {0}", curVal);

}
}

Output:
Entity Name: Student
Entity State: Modified
********Property Values********
Property Name: StudentID
Original Value: 1
Current Value: 1
Property Name: StudentName
Original Value: First Student Name
Current Value: Edited name
Property Name: StandardId
Original Value:
Current Value:

DbEntityEntry enables you to set Added, Modified or Deleted EntityState to


an entity as shown below.
context.Entry(student).State = System.Data.Entity.EntityState.Modified;

DBEntityEntry class has the following important methods:

Method Name Return Type

Description

Collection

Gets an object that represents the collection navigation


property from this entity to a collection of related entiti

DBCollectionEntry

Example:
var studentDBEntityEntry = dbContext.Entry(studentEn
var collectionProperty =
studentDBEntityEntry.Collection<course>(s => s.Cours
ComplexProper
ty

DBComplexProperty
Entry

Gets an object that represents a complex property of th


entity.
Example:
var studentDBEntityEntry = dbContext.Entry(studentEn
var complexProperty =
studentDBEntityEntry.ComplexProperty(stud.StudentSta
);

GetDatabaseVa DBPropertyValues
lues

Queries the database for copies of the values of the tra


entity as they currently exist in the database. Changing
values in the returned dictionary will not update the va
the database. If the entity is not found in the database
null is returned.
Example:
var studentDBEntityEntry = dbContext.Entry(studentEn
var dbPropValues =
studentDBEntityEntry.GetDatabaseValues();

Property

DBPropertyEntry

Gets an object that represents a scalar or complex prop


of this entity.
Example:
var studentDBEntityEntry = dbContext.Entry(studentEn
string propertyName =
studentDBEntityEntry.Property("StudentName").Name;

Reference

DBReferenceEntry

Gets an object that represents the reference (i.e. noncollection) navigation property from this entity to anoth
entity.
Example:
var studentDBEntityEntry = dbContext.Entry(studentEn
var referenceProperty = studentDBEntityEntry.Referenc
=> s.Standard);

Reload

void

Reloads the entity from the database overwriting any

property values with values from the database. The ent


be in the Unchanged state after calling this method.
Example:
var studentDBEntityEntry = dbContext.Entry(studentEn
studentDBEntityEntry.Reload();

Change Tracking in Entity Framework:


Here, you will learn how entity framework tracks changes on entities during
its life time.
Entity framework supports automatic change tracking of the loaded entities
during the life time of the context. DbChangeTracker class gives you all the
information about current entities being tracked by the context.
Please note that every entity must have EntityKey (primary key) property in
order to be tracked by the context. Entity framework will not add any entity
in the conceptual model which does not have an EntityKey property.
The following code snippet shows how context class tracks the entities and
changes occurred in it:

static void Main(string[] args)


{
using (var ctx = new SchoolDBEntities())
{
Console.WriteLine("Find Student");
var std1 = ctx.Students.Find(1);
Console.WriteLine("Context tracking changes of {0} entity.",
ctx.ChangeTracker.Entries().Count());
DisplayTrackedEntities(ctx.ChangeTracker);
Console.WriteLine("Find Standard");

var standard = ctx.Standards.Find(1);


Console.WriteLine("Context tracking changes of {0} entities.",
ctx.ChangeTracker.Entries().Count());
Console.WriteLine("");
Console.WriteLine("Editing Standard");
standard.StandardName = "Edited name";
DisplayTrackedEntities(ctx.ChangeTracker);

Teacher tchr = new Teacher() { TeacherName = "new teacher" };


Console.WriteLine("Adding New Teacher");
ctx.Teachers.Add(tchr);
Console.WriteLine("");
Console.WriteLine("Context tracking changes of {0} entities.",
ctx.ChangeTracker.Entries().Count());
DisplayTrackedEntities(ctx.ChangeTracker);
Console.WriteLine("Remove Student");
Console.WriteLine("");
ctx.Students.Remove(std1);
DisplayTrackedEntities(ctx.ChangeTracker);
}
}
private static void DisplayTrackedEntities(DbChangeTracker
changeTracker)
{
Console.WriteLine("");

var entries = changeTracker.Entries();


foreach (var entry in entries)
{
Console.WriteLine("Entity Name: {0}",
entry.Entity.GetType().FullName);
Console.WriteLine("Status: {0}", entry.State);
}
Console.WriteLine("");
Console.WriteLine("---------------------------------------");
}

Output:
Find Student
Context tracking changes of 1 entity.

Entity Name: EFTutorials.Student


Status: Unchanged

--------------------------------------Find Standard
Context tracking changes of 2 entities.

Editing Standard

Entity Name: EFTutorials.Standard


Status: Modified
Entity Name: EFTutorials.Student
Status: Unchanged

--------------------------------------Adding New Teacher

Context tracking changes of 3 entities.

Entity Name: EFTutorials.Teacher


Status: Added
Entity Name: EFTutorials.Standard
Status: Modified
Entity Name: EFTutorials.Student
Status: Unchanged

--------------------------------------Remove Student

Entity Name: EFTutorials.Teacher


Status: Added
Entity Name: EFTutorials.Standard
Status: Modified
Entity Name: EFTutorials.Student
Status: Deleted

---------------------------------------

As you can see in the above sample code snippet and output, context keeps
track of entities whenever we retrieve, add, modify or delete any entity.
Please notice that context is alive during any of the operations on entities.
Context will not keep track if you do any operation on entities out of its
scope.

Persistence in Entity Framework


There are two scenarios when persisting an entity using EntityFramework,
connected and disconnected scenarios.
Connected Scenario: This is when an entity is retrieved from the database
and persist is used in the same context. Context object doesn't destroy
between entity retrieval and persistence of entities.

Disconnected Scenario: Disconnected scenario is when an entity is


retrieved from the database and the changed entities are submitted using
the different objects in the context. The following example illustrates
disconnected scenario:

As per the above scenario, Context1 is used for read operation and then
Context1 is destroyed. Once entities change, the application submits entities
using Context2 - a different context object.
Disconnected scenario is complex because the new context doesn't know
anything about the modified entity so you will have to instruct the context of

what has changed in the entity. In the figure below, the application retrieves
an entity graph using Context 1 and then the application performs some CUD
(Create, Update, Delete) operations on it and finally, it saves the entity graph
using Context 2. Context 2 doesn't know what operation has been performed
on the entity graph in this scenario.

CRUD Operation in Connected


Scenario:
CRUD operation in connected scenario is a fairly easy task because the
context automatically tracks the changes that happened in the entity during
its lifetime, provided AutoDetectChangesEnabled is true, by default.
Make sure that you have created an Entity Data Model as shown in
the Create Entity Data Modelsection for SchoolDB sample database.
The following example shows how you can add, update, and delete an entity
in the connected scenario (within the scope of context), which in turn will
execute insert, update, and delete commands on the database. Context will
automatically detect the changes and update the state of an entity.

using (var context = new SchoolDBEntities())


{
var studentList = context.Students.ToList<Student>();
//Perform create operation
context.Students.Add(new Student() { StudentName = "New
Student" });
//Perform Update operation
Student studentToUpdate = studentList.Where(s => s.StudentName ==
"student1").FirstOrDefault<Student>();
studentToUpdate.StudentName = "Edited student1";
//Perform delete operation
context.Students.Remove(studentList.ElementAt<Student>(0));

//Execute Inser, Update & Delete queries in the database


context.SaveChanges();
}
Note: If context.Configuration.AutoDetectChangesEnabled
=
false then
context cannot detect changes made to existing entities so do not execute
update query. You need to call context.ChangeTracker.DetectChanges()
before SaveChanges() in order to detect the edited entities and mark their
status as Modified.
Context detects adding and deleting entity, when the operation is performed
only on DbSet. If you perform add and delete entity on a separate collection
or list, then it won't detect these changes.
The following code will NOT insert or delete student. It will only update the
student entity because we are adding and deleting entities from the List and
not from DbSet.

using (var context = new SchoolDBEntities())


{
var studentList = context.Students.ToList<Student>();
//Add student in list
studentList.Add(new Student() { StudentName = "New Student" });
//Perform update operation
Student studentToUpdate = studentList.Where(s => s.StudentName ==
"Student1").FirstOrDefault<Student>();
studentToUpdate.StudentName = "Edited student1";
//Delete student from list
if (studentList.Count > 0)
studentList.Remove(studentList.ElementAt<Student>(0));
//SaveChanges will only do update operation not add and delete

context.SaveChanges();
}

Disconnected Entities:
Before we see how to perform CRUD operation on disconnected entity graph,
let's see how to associate disconnected entity graph with the new context
instance.
There are two things we need to do when we get a disconnected entity graph
or even a single disconnected entity. First, we need to attach entities with the
new context instance and make context aware about these entities. Second,
set appropriate EntityStates to these entities manually because the new
context instance doesn't know anything about the operations performed on
the disconnected entities, so the new context cannot apply the appropriate
EntityState.
The following figure illustrates this process.

Entity Framework API provides some important methods that attaches


disconnected entities to the new context and also set EntityStates to all the
entities of an entity graph.

DbSet.Add():
DbSet.Add() method attaches the entire entity graph to the new context and
automatically applies Added entity state to all the entities.
Consider the following example code.

//disconnected entity graph


Student disconnectedStudent = new Student() { StudentName = "New
Student" };
disconnectedStudent.StudentAddress = new StudentAddress()
{ Address1 = "Address", City = "City1" };
using (var ctx = new SchoolDBEntities())
{
//add disconnected Student entity graph to new context instance ctx
ctx.Students.Add(disconnectedStudent);
// get DbEntityEntry instance to check the EntityState of specified
entity
var studentEntry = ctx.Entry(disconnectedStudent);
var addressEntry = ctx.Entry(disconnectedStudent.StudentAddress);
Console.WriteLine("Student EntityState: {0}",studentEntry.State);
Console.WriteLine("StudentAddress EntityState:
{0}",addressEntry.State);
}
Output:
Student EntityState: Added
StudentAddress EntityState: Added

As per the above example code, we add disconnectedStudent entity graph


using ctx.Students.Add method. Here, parent entity is Student, so we have
added a whole entity graph in Students DbSet. We then get the
DbEntityEntry instance for Student and StudentAddress entities to check the
state of each entity. As you can see in the output, both entities have Added
state.
Thus, use Add method of parent DbSet entity to attach the entire entity
graph to the new context instance with Added state to each entity. This will
execute insert command for all the entities, which will insert new rows in the
appropriate database table.

DbSet.Attach():
DbSet.Attach method attaches a whole entity graph to the new context with
Unchanged entity state.
Consider the following example code.

//disconnected entity graph


Student disconnectedStudent = new Student() { StudentName = "New
Student" };
disconnectedStudent.StudentAddress = new StudentAddress()
{ Address1 = "Address", City = "City1" };
using (var ctx = new SchoolDBEntities())
{
//attach disconnected Student entity graph to new context instance ctx
ctx.Students.Attach(disconnectedStudent);
// get DbEntityEntry instance to check the EntityState of specified
entity
var studentEntry = ctx.Entry(disconnectedStudent);
var addressEntry = ctx.Entry(disconnectedStudent.StudentAddress);
Console.WriteLine("Student EntityState: {0}",studentEntry.State);

Console.WriteLine("StudentAddress EntityState:
{0}",addressEntry.State);
}
Output:
Student EntityState: Unchanged
StudentAddress EntityState: Unchanged

As per the above code, we can attach disconnected entity graph using
DbSet.Attach method. This will attach the entire entity graph to the new
context with Unchanged entity state to all entities.
Thus, Attach method will only attach entity graph to the context, so we need
to find the appropriate entity state for each entity and apply it manually.

DbContext.Entry():
Entry method of DbContext returns DbEntityEntry instance for a specified
entity. DbEntityEntry can be used to change the state of an entity.
DbContext.Entry(disconnectedEntity).state = EntityState.Added/Modified/Deleted/Unchanged

This method attaches a whole entity graph to the context with specified state
to the parent entity and set the state of other entities, as shown in the
following table.
Parent Entity State

Entity State of child entities

Added

Added

Modified

Unchanged

Deleted

All child entities will be null

Add New Entity using DBContext in


Disconnected Scenario:
In this chapter you will learn how to add new entity in DbContext in
the disconnected scenario, which in turn inserts a new row in a database
table.
If you use Database-First approach, then create an Entity Data Model as
shown in the previous chapter for SchoolDB sample database. Or, if you use
Code-First or Model-First approach, then create entities and context classes.
In any case, entities and context classes will look similar.
Here, we will see how to add single Student entity (not entity graph). The
following is a Student entity.

using System;
using System.Collections.Generic;
public partial class Student
{
public Student()
{
this.Courses = new HashSet<Course>();
}
public int StudentID { get; set; }
public string StudentName { get; set; }
public Nullable<int> StandardId { get; set; }
public byte[] RowVersion { get; set; }
public virtual Standard Standard { get; set; }
public virtual StudentAddress StudentAddress { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}

The following is a context class.

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Core.Objects;
using System.Linq;
public partial class SchoolDBEntities : DbContext
{
public SchoolDBEntities()
: base("name=SchoolDBEntities")
{
}
protected override void OnModelCreating(DbModelBuilder
modelBuilder)
{
}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Standard> Standards { get; set; }
public virtual DbSet<Student> Students { get; set; }
public virtual DbSet<StudentAddress> StudentAddresses { get; set; }
public virtual DbSet<Teacher> Teachers { get; set; }
}

The following code shows how to save a single entity.

class Program
{

static void Main(string[] args)


{
// create new Student entity object in disconnected scenario (out of
the scope of DbContext)
var newStudent = new Student();
//set student name
newStudent.StudentName = "Bill";
//create DBContext object
using (var dbCtx = new SchoolDBEntities())
{
//Add Student object into Students DBset
dbCtx.Students.Add(newStudent);
// call SaveChanges method to save student into database
dbCtx.SaveChanges();
}
}
}

As you can see in the above code snippet, first, we have created a new
Student entity object and set StudentName to 'Bill'. Second, we have created
a new DBContext object and added newStudent into Students EntitySet.
Third, we called SaveChanges method of DBContext which will execute the
following insert query to the database.

exec sp_executesql N'INSERT [dbo].[Student]([StudentName],


[StandardId])
VALUES (@0, NULL)
SELECT [StudentID], [RowVersion]
FROM [dbo].[Student]
WHERE @@ROWCOUNT > 0 AND [StudentID] = scope_identity(),@0='Bill'

Alternatively, we can also add entity into DBContext.Entry and mark it as


Added which results in the same insert query:

class Program
{
static void Main(string[] args)
{
// create new Student entity object in disconnected scenario (out of
the scope of DbContext)
var newStudent = new Student();
//set student name
newStudent.StudentName = "Bill";
//create DBContext object
using (var dbCtx = new SchoolDBEntities())
{
//Add newStudent entity into DbEntityEntry and mark EntityState
to Added
dbCtx.Entry(newStudent).State =
System.Data.Entity.EntityState.Added;
// call SaveChanges method to save new Student into database
dbCtx.SaveChanges();
}
}
}

So, in this way, you can add a new single entity in the disconnected scenario.
In the next chapter, you will learn how to update an existing single entity in
the disconnected scenario.

Update Existing Entity using DBContext


in Disconnected Scenario:
In this chapter, you will learn how to update a single entity in a disconnected
scenario.
If you use Database-First approach, then create an Entity Data Model as
shown in the previous chapter for SchoolDB sample database. Or, if you use
Code-First or Model-First approach, then create entities and context classes.
In any case, entities and context classes will look similar.
Here, we will see how to update a single Student entity (not entity graph).
The following is a Student entity.

using System;
using System.Collections.Generic;
public partial class Student
{
public Student()
{
this.Courses = new HashSet<Course>();
}
public int StudentID { get; set; }
public string StudentName { get; set; }
public Nullable<int> StandardId { get; set; }
public byte[] RowVersion { get; set; }
public virtual Standard Standard { get; set; }
public virtual StudentAddress StudentAddress { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}

The following is a context class.

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Core.Objects;
using System.Linq;
public partial class SchoolDBEntities : DbContext
{
public SchoolDBEntities()
: base("name=SchoolDBEntities")
{
}
protected override void OnModelCreating(DbModelBuilder
modelBuilder)
{
}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Standard> Standards { get; set; }
public virtual DbSet<Student> Students { get; set; }
public virtual DbSet<StudentAddress> StudentAddresses { get; set; }
public virtual DbSet<Teacher> Teachers { get; set; }
}

The following example shows how to update a Student entity in the


disconnected scenario:

Student stud;
//1. Get student from DB
using (var ctx = new SchoolDBEntities())
{

stud = ctx.Students.Where(s => s.StudentName == "New


Student1").FirstOrDefault<Student>();
}
//2. change student name in disconnected mode (out of ctx scope)
if (stud != null)
{
stud.StudentName = "Updated Student1";
}
//save modified entity using new Context
using (var dbCtx = new SchoolDBEntities())
{
//3. Mark entity as modified
dbCtx.Entry(stud).State =
System.Data.Entity.EntityState.Modified;
//4. call SaveChanges
dbCtx.SaveChanges();
}

As you see in the above code snippet, we are doing the following steps:
1. Get the existing student from DB.
2. Change the student name out of Context scope (disconnected mode)
3. Pass the modified entity into the Entry method to get its DBEntityEntry
object and then mark its state as Modified
4. Call SaveChanges() method to update student information into the
database.
SaveChanges will send the following update query to the database:

exec sp_executesql N'update [dbo].[Student]

set [StudentName] = @0, [StandardId] = @1


where ([StudentID] = @2)',N'@0 varchar(50),
@1 int,@2 int',@0='Updated Student1',@1=299,@2=267

In this way, we can easily update a single entity using DBContext in the
disconnected mode.
DbContext.Entry method returns an instance of DBEntityEntry for a specified
Entity. An instance of DbEntityEntry class providea access to information
about a given entity and its state. You can change the state of an entity to
Added, Updated, or Deleted.
In the next chapter you will learn how to delete a single entity in the
disconnected mode.

Delete Entity using DBContext in


Disconnected Scenario:
We used the Entry() method of DbContext to mark EntityState as Modified in
the previous chapter. In the same way, we can use the Entry() method to
attach a disconnected entity to the context and mark its state to Deleted.

Student studentToDelete;
//1. Get student from DB
using (var ctx = new SchoolDBEntities())
{
studentToDelete = ctx.Students.Where(s => s.StudentName ==
"Student1").FirstOrDefault<Student>();
}
//Create new context for disconnected scenario
using (var newContext = new SchoolDBEntities())
{

newContext.Entry(studentToDelete).State =
System.Data.Entity.EntityState.Deleted;
newContext.SaveChanges();
}

The code shown above results in the following delete query which deletes the
row from Teacher table.

delete [dbo].[Student]
where ([StudentId] = @0)',N'@0 int',@0=1

Thus, you can delete a single entity in disconnected scenario.

Add Entity Graph using DbContext:


Adding entity graph with all new entities is a simple task. We can use
DbSet.Add() method to attach a whole entity graph to the context and set all
the entity's states to Added as we have seen in theprevious section.
The following example adds a student entity graph in disconnected mode,
using the DbSet.Add() method which marks the added state to all the
entities:

//Create student in disconnected mode


Student newStudent = new Student() { StudentName = "New Single
Student" };
//Assign new standard to student entity
newStudent.Standard = new Standard() { StandardName = "New
Standard" };
//add new course with new teacher into student.courses
newStudent.Courses.Add(new Course() { CourseName = "New Course for
single student", Teacher = new Teacher() { TeacherName = "New Teacher"
} });

using (var context = new SchoolDBEntities())


{
context.Students.Add(newStudent);
context.SaveChanges();
Console.WriteLine("New Student Entity has been added with new
StudentId= " + newStudent.StudentID.ToString());
Console.WriteLine("New Standard Entity has been added with new
StandardId= " + newStudent.StandardId.ToString());
Console.WriteLine("New Course Entity has been added with new
CourseId= " + newStudent.Courses.ElementAt(0).CourseId.ToString());
Console.WriteLine("New Teacher Entity has been added with new
TeacherId= " + newStudent.Courses.ElementAt(0).TeacherId.ToString());
}
Output:
New Student Entity has been added with new StudentId= 14
New Standard Entity has been added with new StandardId= 6
New Course Entity has been added with new CourseId= 7
New Teacher Entity has been added with new TeacherId= 9

This executes the following DDL statements to the database:

exec sp_executesql N'INSERT [dbo].[Standard]([StandardName],


[Description])
VALUES (@0, NULL)
SELECT [StandardId]
FROM [dbo].[Standard]
WHERE @@ROWCOUNT > 0 AND [StandardId] = scope_identity()',N'@0
varchar(50)',@0='New Standard'
go

exec sp_executesql N'INSERT [dbo].[Student]([StudentName],


[StandardId])
VALUES (@0, @1)
SELECT [StudentID]
FROM [dbo].[Student]
WHERE @@ROWCOUNT > 0 AND [StudentID] = scope_identity()',N'@0
varchar(50),@1 int',@0='New Single Student',@1=61
go
exec sp_executesql N'INSERT [dbo].[Teacher]([TeacherName],
[StandardId])
VALUES (@0, NULL)
SELECT [TeacherId]
FROM [dbo].[Teacher]
WHERE @@ROWCOUNT > 0 AND [TeacherId] = scope_identity()',N'@0
varchar(50)',@0='New Teacher'
go
exec sp_executesql N'INSERT [dbo].[Course]([CourseName], [Location],
[TeacherId])
VALUES (@0, NULL, @1)
SELECT [CourseId]
FROM [dbo].[Course]
WHERE @@ROWCOUNT > 0 AND [CourseId] = scope_identity()',N'@0
varchar(50),@1 int',@0='New Course for single student',@1=93
go
exec sp_executesql N'INSERT [dbo].[StudentCourse]([StudentId],
[CourseId])
VALUES (@0, @1)
',N'@0 int,@1 int',@0=43,@1=72
go

Thus, there is no difference when you add a single entity or entity graph in
disconnected or connected scenario. Make sure that all the entities are new.
Learn how to update entity graph in disconnected scenario in the next
section.

Update Entity Graph using DbContext:


Updating an entity graph in disconnected scenario is a complex task. It is
easy to add a new entity graph in disconnected mode, but to update an
entity graph needs careful design consideration.
The problem in updating an entity graph in the disconnected scenario, is that
the context doesn't know what operation was performed on it at the client
side. As per the following figure, the new context doesn't know the state of
each entity:

We need to identify the states of each entity in the entity graph, before
calling the SaveChages() method of context. There are different patterns to

identify entity state, which we need to consider in designing data layer with
Entity Framework.

Patterns of Identifying Entity State in disconnected


scenario:
There are several ways (some shown below) to identify an entity state in
disconnected scenario:
1. Using PrimaryKey (Id) property of an entity
2. Having state property in entity set
Note: You can create your own design to identify an entity state based on
your architecture. This is just for learning purposes.

1) Using PrimaryKey property of an entity:


You can use the PrimaryKey (Id) property of each entity to determine its
entity state. However, you have to decide which of the following architectural
rule to use:

Each type of entity must have Id property (PK)

Default value of Id property should be 0

As you can see in the figure shown above, the client fetches the Standard
and Teacher entity graph and does some operations on it and then sends it to
Context 2 to save the changes.
In the disconnected scenario, context2 doesn't know the state of each entity.
It has to determine the state of the Standard entity by using StandardId and
the state of the Teacher entity by using TeacherId property. If StandardId
and TeacherID value is zero, that means it is a new entity and if it is not zero
then it is a modified entity.
In the above figure, Standard, Teacher 1, and Teacher 2 have a non-zero Id
property value so they are marked as Modified and Teacher 3 Id is zero so it
is marked as Added.
The code snippet shown below uses Id property to mark an entity state:

Standard disconnectedStandard = null;


using (var context = new SchoolDBEntities())

{
context.Configuration.ProxyCreationEnabled = false;
disconnectedStandard = context.Standards.Where(s => s.StandardId
== 58).Include(s => s.Teachers).FirstOrDefault<Standard>();
}
//Update Standard in disconnected mode
disconnectedStandard.StandardName = "Edited Standard Name";
//Update teachers collection by editing first teacher and adding new
teacher
disconnectedStandard.Teachers.ElementAt(0).TeacherName = "Edited
Teacher Name";
disconnectedStandard.Teachers.Add(new Teacher() { TeacherName =
"New Teacher", StandardId = disconnectedStandard.StandardId });
using (var newContext = new SchoolDBEntities())
{
//mark standard based on StandardId
newContext.Entry(disconnectedStandard).State =
disconnectedStandard.StandardId == 0 ? EntityState.Added :
EntityState.Modified;
//mark teacher based on StandardId
foreach (Teacher tchr in disconnectedStandard.Teachers)
newContext.Entry(tchr).State = tchr.TeacherId == 0 ?
EntityState.Added : EntityState.Modified;

newContext.SaveChanges();
}
Advantages:

No need for extra coding/processing to determine entity state.

Good performance.

Disadvantages:

Every entity type needs to have an Id property. It cannot determine states of an entity that
do not have Id property.

Cannot identify an Unchanged entity. It is set to Modified state even if the entity is not
changed at all. So, there is an unnecessary database update statement for an
unchanged entity.

Cannot handle delete entity scenario. It needs to handle deletion separately.

2) Having State property in every entity:


Another way to determine entity state is to have a State property in every
entity type and set an appropriate state from the client side in disconnected
mode. Then we just need to set the entity state as the state property of an
entity object before calling SaveChanges of the new context.
Example:
First of all, create an IEntityState interface with enum property called
ObjectState:

interface IEntityObjectState
{
EntityObjectState ObjectState { get; set; }
}
public enum EntityObjectState
{
Added,
Modified,
Deleted,
Unchanged
}

Now, implement an IEntityObjectState in each entity class, e.g. Standard and


Teacher entity, as shown below:

public partial class Standard:IEntityObjectState


{
public Standard()
{
this.Students = new HashSet<Student>();
this.Teachers = new HashSet<Teacher>();
}
public int StandardId { get; set; }
public string StandardName { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students { get; set; }
public virtual ICollection<Teacher> Teachers { get; set; }
[NotMapped]
public EntityObjectState ObjectState
{
get;
set;
}
}
public partial class Teacher:IEntityObjectState
{
public Teacher()
{
this.Courses = new HashSet<Course>();
}
public int TeacherId { get; set; }

public string TeacherName { get; set; }


public Nullable<int> StandardId { get; set; }
public virtual ICollection<Course> Courses { get; set; }
public virtual Standard Standard { get; set; }
[NotMapped]
public EntityObjectState ObjectState
{
get;
set;
}
}
Set the appropriate state in disconnected mode on client side:

Teacher existingTeacher = null;


using (var context = new SchoolDBEntities())
{
context.Configuration.ProxyCreationEnabled = false;
existingTeacher = context.Teachers.FirstOrDefault<Teacher>();
}
Standard disconnectedStandard = new Standard() { StandardName =
"New Standard", ObjectState = EntityObjectState.Added };
existingTeacher.ObjectState = EntityObjectState.Modified;
//add existing teacher(in db) to standard
disconnectedStandard.Teachers.Add(existingTeacher);
//add new standard
disconnectedStandard.Teachers.Add(new Teacher() { TeacherName =
"New teacher", StandardId = disconnectedStandard.StandardId,
ObjectState = EntityObjectState.Added });

Set the entity state as per ObjectState before calling SaveChanges.

using (var newContext = new SchoolDBEntities())


{
//check the ObjectState property and mark appropriate EntityState
if (disconnectedStandard.ObjectState == EntityObjectState.Added)
newContext.Entry(disconnectedStandard).State =
System.Data.Entity.EntityState.Added;
else if (disconnectedStandard.ObjectState ==
EntityObjectState.Modified)
newContext.Entry(disconnectedStandard).State
=System.Data.Entity.EntityState.Modified;
else if (disconnectedStandard.ObjectState ==
EntityObjectState.Deleted)
newContext.Entry(disconnectedStandard).State =
System.Data.Entity.EntityState.Deleted;
else
newContext.Entry(disconnectedStandard).State =
System.Data.Entity.EntityState.Unchanged;
//check the ObjectState property of each teacher and mark appropriate
EntityState
foreach (Teacher tchr in disconnectedStandard.Teachers)
{
if (tchr.ObjectState == EntityObjectState.Added)
newContext.Entry(tchr).State =
System.Data.Entity.EntityState.Added;
else if (tchr.ObjectState == EntityObjectState.Modified)
newContext.Entry(tchr).State =
System.Data.Entity.EntityState.Modified;
else if (tchr.ObjectState == EntityObjectState.Deleted)
newContext.Entry(tchr).State =
System.Data.Entity.EntityState.Deleted;
else

newContext.Entry(tchr).State =
System.Data.Entity.EntityState.Unchanged;
}
//save changes
newContext.SaveChanges();
}
Advantages:

No need for extra coding/processing to determine the entity state

Handles Added, Modified, Deleted, and Unchanged states properly

No unnecessary update call for unchanged entities.

Disadvantage:

Need to set the appropriate states of each entity in disconnected mode. So there is a
need to be extra careful in disconnected mode.

Concurrency in Entity Framework:


Entity Framework supports Optimistic Concurrency by default. In the
optimistic concurrency, EF saves the entity to the database, assuming that
the same data has not changed since the entity was loaded. If it determines
that the data has changed, then an exception is thrown and you must resolve
the conflict before attempting to save it again.
Let's see how to handle optimistic concurrency with Student entity.
First of all, you need to have a rowversion column in the Student table in
order to handle concurrency with Student entity. Rowversion is a datatype in
the SQL Server that automatically generates unique binary number whenever
the insert or update operation is performed in a table. The rowversion
datatype is simply an incrementing number. Rowversion is a similar to the
timestamp datatype.
Create a new column RowVersion in Student table with timestamp datatype
as shown below:

Note: The value of RowVersion will be added and updated automatically by


the database during the Insert and Update operation.
Now, create a new Entity Data Model as shown in Create Entity Data
Model section or if you already have an EDM then update it by right clicking
on designer -> Update Model From Database -> Refresh Student table.
Now, you will see the RowVersion property added in the Student entity.
Then, you need to set the concurrency mode to fixed by right clicking
on RowVersion property in the Student entity (right click on RowVersion
property not Student entity) -> select Property. Change Concurrency Mode to
Fixed from None in the property window as shown below:

EF will now include a RowVersion column in the where clause, whenever you
do an update operation and if the rowversion value is different than in the
where clause then it will throwDbUpdateConcurrencyExection.
The following code shows that User1 and User2 get the same student and
update StudentName at the same time:

Student student1WithUser1 = null;


Student student1WithUser2 = null;

//User 1 gets student


using (var context = new SchoolDBEntities())
{
context.Configuration.ProxyCreationEnabled = false;
student1WithUser1 = context.Students.Where(s => s.StudentID ==
1).Single();
}
//User 2 also get the same student
using (var context = new SchoolDBEntities())
{
context.Configuration.ProxyCreationEnabled = false;
student1WithUser2 = context.Students.Where(s => s.StudentID ==
1).Single();
}
//User 1 updates Student name
student1WithUser1.StudentName = "Edited from user1";
//User 2 updates Student name
student1WithUser2.StudentName = "Edited from user2";

User1 saves his changes before User2. So when user2 tries to save the
changes, he will get concurrency exection:

//User 1 saves changes first


using (var context = new SchoolDBEntities())
{
try
{
context.Entry(student1WithUser1).State = EntityState.Modified;
context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)

{
Console.WriteLine("Optimistic Concurrency exception occured");
}
}
//User 2 saves changes after User 1.
//User 2 will get concurrency exection
//because CreateOrModifiedDate is different in the database
using (var context = new SchoolDBEntities())
{
try
{
context.Entry(student1WithUser2).State = EntityState.Modified;
context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
Console.WriteLine("Optimistic Concurrency exception occured");
}
}

Concurrency in Code-First:
You can create a timestamp property in code-first by using [Timestamp]
attribute. Make sure that the property type is byte[] because timestamp is
binary in C#.

[Timestamp]
public byte[] RowVersion { get; set; }
EF includes a property in the where clause, during the update operation, if
the property is marked with the Timestamp attribute.
You can resolve concurrency exceptions many ways. Visit msdn for detailed
information on how to resolve optimistic concurrency.

Stored Procedure in Entity Framework:


Entity Framework has the ability to automatically build native commands for
the database based on your LINQ to Entities or Entity SQL queries, as well
as, build the commands for inserting, updating, or deleting data. You may
want to override these steps and use your own predefined stored procedures.
You can use stored procedures either to get the data or to add/update/delete
the records to one or multiple database tables.
Stored procedures and user-defined functions (UDFs) in the database are
represented as functions in entity framework. EDM won't have any entity for
the stored procedures in the EDM designer.
Here, we will add the following stored procedure GetCoursesByStudentId into
EDM. This procedure returns all the courses assigned to a particular student:

CREATE PROCEDURE [dbo].[GetCoursesByStudentId]


-- Add the parameters for the stored procedure here
@StudentId int = null
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
select c.courseid, c.coursename,c.Location, c.TeacherId
from student s
left outer join studentcourse sc on sc.studentid = s.studentid
left outer join course c on c.courseid = sc.courseid
where s.studentid = @StudentId
END
First, create a new ADO.Net Entity Data Model using EF Designer from
database.

Select GetCoursesByStudentId. Make sure that the Import selected stored


procedures and functions into the entity model checkbox is selected
and then click Finish.

You will see GetCoursesByStudentId added in Function Imports with new


complex type GetCoursesByStudentId_Result in the Model Browser.
Whenever you import a stored procedure into a model, it creates a new
complex type with the name {sp name}_Result by default.

GetCoursesByStudentId returns the same fields defined in Course entity. So


we don't need to add a new complex type for the returned data from
GetCoursesByStudentId. You can change it by right clicking on
GetCoursesByStudentId in function imports and selecting Edit. Check Entities
and select Course from dropdown in popup window as shown below:

You will see the function in the context class for GetCoursesByStudentId as
shown below:

Now, GetCoursesByStudentId can be called and the result shown below will
be returned:

using (var context = new SchoolDBEntities())


{
var courses = context.GetCoursesByStudentId(1);
foreach (Course cs in courses)
Console.WriteLine(cs.CourseName);
}
The code shown above will execute the following statement:
exec [dbo].[GetCoursesByStudentId] @StudentId=1

You will learn how to use stored procedures for CUD operation in the next
chapter.

CRUD using Stored Procedure:


In the previous chapter, we have seen how to get data using a stored
procedure. In this chapter, we will use stored procedures for CUD (create,
update, delete) operation using DbContext. That means context will execute
stored procedures instead of DDL statements on context.SaveChanges().

We will use the following stored procedures:


1. sp_InsertStudentInfo stored procedure to insert a new student into the
database
2. sp_UpdateStudent to update the student
3. sp_DeleteStudent to delete the student in the database.
Sp_InsertStudentInfo:

CREATE PROCEDURE [dbo].[sp_InsertStudentInfo]


-- Add the parameters for the stored procedure here
@StandardId int = null,
@StudentName varchar
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
INSERT INTO [SchoolDB].[dbo].[Student]([StudentName],
[StandardId])
VALUES(@StudentName, @StandardId)
SELECT SCOPE_IDENTITY() AS StudentId
END
sp_UpdateStudent:

CREATE PROCEDURE [dbo].[sp_UpdateStudent]


-- Add the parameters for the stored procedure here
@StudentId int,
@StandardId int = null,
@StudentName varchar
AS

BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Update [SchoolDB].[dbo].[Student]
set StudentName = @StudentName,StandardId = @StandardId
where StudentID = @StudentId;
END
sp_DeleteStudent

CREATE PROCEDURE [dbo].[sp_DeleteStudent]


-- Add the parameters for the stored procedure here
@StudentId int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DELETE FROM [dbo].[Student]
where StudentID = @StudentId
END

First of all, add these stored procedures into EDM and make sure that
the Import selected stored procedures and function into the entity
model checkbox is unchecked as we will map these procedures with
Student entity directly.

Now, Model Browser will add procedures into Storage model but not in
Function Imports

In the EDM designer, right click on Student entity and select Stored
Procedure Mapping to open Mapping details:

In the Mapping Details, you will see <Select Insert Function>, <Select
Update Function>, and <Select Delete Function>. Select the appropriate
stored procedure for each one, e.g. Select sp_InsertStudentInfo for Insert
function, as shown below:

sp_InsertStudentInfo returns new auto generated StudentId. Map that with


Student Entitys StudentID as shown below:

Complete the mapping of Insert, Update and Delete procedures as shown


below:

Now, we need to validate it before executing to ensure that there will not be
a run time error. To accomplish this, right click on Student entity in the
designer and click Validate and make sure that there are no warnings or
errors:

Now you can add, update, and delete student as shown below:

using (var context = new SchoolDBEntities())


{
Student newStudent = new Student() { StudentName = "New Student
using SP"};
context.Students.Add(newStudent);
//will execute sp_InsertStudentInfo
context.SaveChanges();
newStudent.StudentName = "Edited student using SP";
//will execute sp_UpdateStudent
context.SaveChanges();
context.Students.Remove(newStudent);
//will execute sp_DeleteStudentInfo
context.SaveChanges();
}
The code shown above will execute the following stored procedures on each
SaveChanges():

exec [dbo].[sp_InsertStudentInfo]
@StandardId=NULL,@StudentName='New Student using SP'
go
exec [dbo].[sp_UpdateStudent]
@StudentId=47,@StandardId=NULL,@StudentName='Edited student
using SP'
go
exec [dbo].[sp_DeleteStudent] @StudentId=47
go
Note: Once context calls SaveChanges after adding a new student, it will
assign new StudentID to StudentID property of the Student entity because
sp_InsertStudentInfo returns StudentId. This is necessary in order to use
that entity object for further operation.

Enum in Entity Framework:


You can now have an Enum in Entity Framework 5.0 onwards. EF 5 should
target .NET framework 4.5 in order to use Enum.
Enum can be created for the following data types:

Int16

Int32

Int64

Byte

SByte

You can create and use an Enum type in your entity data model in three
ways:
1. Convert an existing property of entity to Enum from EDM designer
2. Add a new Enum from EDM designer
3. Use an existing Enum type from different namespace
For the purposes of this demo, we have included the TeacherType integer
column in the Teacher table of SchoolDB. TeacherType 1 is for permanent
teachers, 2 is for contractor teachers, and 3 is for guest teachers.
1. Convert an existing property to Enum:
Next, we will see how to convert a TeacherType to an Enum.
First, right click on the TeacherType property of a Teacher entity and click
'Convert to Enum' in the context menu.

It will open the 'Add Enum Type' dialog box where you can enter the 'Enum
Type Name' and, select 'Underlying Type' and Enum member names. For
example:

After converting it to Enum, you can see TeacherType as Enum Type in the
Model Browser, as shown below:

Also, you can see that the type of the TeacherType property is converted to
TeacherType Enum:

Now, you can use TeacherType Enum in CRUD operation using DBContext.
For example:

using (var ctx = new SchoolDBEntities())


{
Teacher tchr = new Teacher();
tchr.TeacherName = "New Teacher";

tchr.TeacherType = TeacherType.Permanent;
ctx.Teachers.Add(tchr);
ctx.SaveChanges();
}

2. Add New Enum from Designer:


You can also add a new Enum by right clicking on EDM designer and selecting
Add Enum Type. It will open the same 'Add Enum Type' dialog box, where
you can enter enum members.

After creating an Enum Type you can change the type of the TeacherType
property to the newly created TeacherType Enum from the property window.
3. If you already have Enum type created in your code, then you can
use that as a data type of any entity property.
To use an existing Enum type, right click on designer Add New Enum
Type. Enter the Enum Type Name in the dialog box. Do not enter the member
as you already have that in your code.
Now, select 'Reference external type' checkbox and enter the namespace of
your existing enum and click OK. This will add the Enum type in the Model
browser. Then, you can assign this Enum type to any property of an entity
from the property window.
Note: Select 'Set Flags attribute' if you want to use bitwise operators with
your Enum.

Spatial Data type support in Entity


Framework 5.0
MS SQL Server 2008 introduced two spatial data types, geography and
geometry. Geography represents data in a round-earth coordinate system
and geometry represent data in a Euclidean (flat) coordinate system.
Entity Framework supports spatial data types DbGeography and DbGeometry
since version 5.0. Let's see how we can use these data types.
For demo purposes, we have changed the data type of the Location column
of Course table to geography in SQL Server 2008 as shown below:

Now, create an entity data model (.edmx) after having geography column in
the database as shown in previous chapter section. After creating EDM, you

can see that the type of Location property


System.Data.Spatial.DBGeography as shown below:

of

Course

entity

is

public partial class Course


{
public Course()
{
this.Students = new HashSet<Student>();
}
public int CourseId { get; set; }
public string CourseName { get; set; }
public Nullable<int> TeacherId { get; set; }
public System.Data.Spatial.DbGeography Location { get; set; }
public virtual Teacher Teacher { get; set; }
public virtual ICollection<Student> Students { get; set; }
}

You can now use the Location property in CRUD operation using DBContext
as shown in the following example.

using (var ctx = new SchoolDBEntities())


{
ctx.Courses.Add(new Course() { CourseName = "New Course",
Location = DbGeography.FromText("POINT(-122.360
47.656)") });
ctx.SaveChanges();
}

Visit MSDN for more information on geography data type and geometry data
type of MS SQL Server 2008.

Table-Valued Function in Entity


Framework 5.0
Entity Framework 5.0 supports Table-valued functions of SQL Server.
Table-valued functions are similar to stored procedure with one key
difference: the result of TVF is composable which means that it can be used
in a LINQ query.
We have created a TVF GetCourseListByStudentID in the database that will
return all the courses of a particular student. For example:

USE [SchoolDB]
GO
/****** Object: UserDefinedFunction [dbo].[GetCourseListByStudentID]
*/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[GetCourseListByStudentID]
(
-- Add the parameters for the function here
@studentID int
)
RETURNS TABLE
AS
RETURN
(

-- Add the SELECT statement with parameter references here


select c.courseid, c.coursename,c.Location, c.TeacherId
from student s left outer join studentcourse sc on sc.studentid =
s.studentid left outer join course c on c.courseid = sc.courseid
where s.studentid = @studentID
)

Now, update your EDM and add this TVF into your EDM. Right click on the
designer select Update Model from the Database..

Expand Stored Procedures and Functions node expand schema node (dbo
schema in our case) select 'GetCourseListByStudentID' and click Finish.
Make sure that the checkbox for 'Import selected procedures and functions
into the entity model' is checked (this will import the function automatically).

After you imported the function, you can verify it: Open Model Browser
expand Function
Imports
right
click
on
imported function
'GetCourseListByStudentID' click Edit:

You can see that EDM has automatically created the complex type
GetCourseListByStudentID_Result as a return collection type.

You can also select an existing entity as a return type if TVF returns the same
columns as entity:

Now, you can use TVF with DBContext. For example:

using (var ctx = new SchoolDBEntities())


{
//Execute TVF and filter result
var courseList = ctx.GetCourseListByStudentID(1).Where(c =>
c.Location == "City1")
.ToList<GetCourseListByStudentID_Result>();

Console.WriteLine("Course Name: {0}, Course Location: {1}",


cs.CourseName, cs.Location);
}

Local Data
The Local property of DBSet provides simple access to the entities that are
currently being tracked by the context, and have not been marked as
Deleted. Local keeps track of entities whose entity state is added, modified
and unchanged. For example:

using (var ctx = new SchoolDBEntities())


{
ctx.Students.Add(new Student() { StudentName = "New
Student1" });
ctx.Students.Remove(ctx.Students.Find(270));

// Loop over the unicorns in the context.


Console.WriteLine("In Local: ");
foreach (var student in ctx.Students.Local)
{
Console.WriteLine("Found {0}: {1} with state {2}",
student.StudentID, student.StudentName,
ctx.Entry(student).State);
}
// Perform a query against the database.
Console.WriteLine("\nIn DbSet query: ");
foreach (var student in ctx.Students)

{
Console.WriteLine("Found {0}: {1} with state {2}",
student.StudentID, student.StudentName,
ctx.Entry(student).State);
}
}

Output:
In Local :
Found 0: New Student1 with state Added
Found 2: Student2 with state Unchanged
Found 3: Student3 with state Unchanged
In DbSet query:
Found 1: Student1 with state Deleted
Found 2: Student2 with state Unchanged
Found 3: Student3 with state Unchanged

Note: Local is an ObservableCollection, so it is not advisable to use it, to


maintain good performance, if used with DBSet., as DBSet keeps track of
thousands of entities.

Eager Loading:

Eager loading is the process whereby a query for one type of entity also
loads related entities as part of the query. Eager loading is achieved using
the Include method of IQueryable.
The code snippet shown below demonstrates eager loading, where Standard
entity will also be loaded with Student entity using the Include() method:
LINQ Query Syntax:

using (var context = new SchoolDBEntities())


{
var res = (from s in context.Students.Include("Standard")
where s.StudentName == "Student1"
select s).FirstOrDefault<Student>();
}
LINQ Method Syntax:

using (var ctx = new SchoolDBEntities())


{
stud = ctx.Students.Include("Standard")
.Where(s => s.StudentName ==
"Student1").FirstOrDefault<Student>();
}

The code shown above will result in following SQL query:

SELECT TOP (1)


[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent2].[StandardId] AS [StandardId],
[Extent2].[StandardName] AS [StandardName],
[Extent2].[Description] AS [Description]

LEFT OUTER JOIN [dbo].[Standard] AS [Extent2] ON [Extent1].[StandardId]


= [Extent2].[StandardId]
WHERE 'Student1' = [Extent1].[StudentName]

Use Lambda Expression:


You can also use linq lambda expression in Include method. For this, take a
reference ofSystem.Data.Entity namespace and use lambda expression as
shown below.

using System;
using System.Data.Entity;
class Program
{
static void Main(string[] args)
{
using (var ctx = new SchoolDBEntities())
{
stud = ctx.Students.Include(s => s.Standard)
.Where(s => s.StudentName == "Student1")
.FirstOrDefault<Student>();
}
}
}

The code shown above will result in the following SQL query:

SELECT TOP (1)


[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],

[Extent2].[StandardId] AS [StandardId],
[Extent2].[StandardName] AS [StandardName],
[Extent2].[Description] AS [Description]
FROM [dbo].[Student] AS [Extent1]
LEFT OUTER JOIN [dbo].[Standard] AS [Extent2] ON [Extent1].[StandardId]
= [Extent2].[StandardId]
WHERE 'Student1' = [Extent1].[StudentName]

Load multiple levels of related entities:


You can also eagerly load multiple levels of related entities. The code snippet
shown below loads related Student, Standard and Teachers:

using (var ctx = new SchoolDBEntities())


{
stud = ctx.Students.Include("Standard.Teachers")
.Where(s => s.StudentName == "Student1")
.FirstOrDefault<Student>();
}

Or using lambda expression as below.

using (var ctx = new SchoolDBEntities())


{
stud = ctx.Students.Include(s => s.Standard.Teachers)
.Where(s => s.StudentName == "Student1")
.FirstOrDefault<Student>();
}

The code shown above results in the following SQL query:

SELECT [Project2].[StudentID] AS [StudentID],

[Project2].[StudentName] AS [StudentName],
[Project2].[StandardId] AS [StandardId],
[Project2].[StandardName] AS [StandardName],
[Project2].[Description] AS [Description],
[Project2].[C1] AS [C1],
[Project2].[TeacherId] AS [TeacherId],
[Project2].[TeacherName] AS [TeacherName],
[Project2].[StandardId1] AS [StandardId1]
FROM ( SELECT
[Limit1].[StudentID] AS [StudentID],
[Limit1].[StudentName] AS [StudentName],
[Limit1].[StandardId1] AS [StandardId],
[Limit1].[StandardName] AS [StandardName],
[Limit1].[Description] AS [Description],
[Project1].[TeacherId] AS [TeacherId],
[Project1].[TeacherName] AS [TeacherName],
[Project1].[StandardId] AS [StandardId1],
CASE WHEN ([Project1].[TeacherId] IS NULL) THEN CAST(NULL AS int)
ELSE 1 END AS [C1]
FROM (SELECT TOP (1) [Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName], [Extent1].[StandardId] AS
[StandardId2], [Extent2].[StandardId] AS [StandardId1], [Extent2].
[StandardName] AS [StandardName], [Extent2].[Description] AS
[Description]
FROM [dbo].[Student] AS [Extent1]
LEFT OUTER JOIN [dbo].[Standard] AS [Extent2] ON [Extent1].
[StandardId] = [Extent2].[StandardId]
WHERE 'updated student' = [Extent1].[StudentName] ) AS [Limit1]
LEFT OUTER JOIN (SELECT
[Extent3].[TeacherId] AS [TeacherId],
[Extent3].[TeacherName] AS [TeacherName],
[Extent3].[StandardId] AS [StandardId]
FROM [dbo].[Teacher] AS [Extent3]

WHERE [Extent3].[StandardId] IS NOT NULL ) AS [Project1] ON


[Limit1].[StandardId2] = [Project1].[StandardId]
) AS [Project2]
ORDER BY [Project2].[StudentID] ASC, [Project2].[StandardId] ASC,
[Project2].[C1] ASC

Learn how Entity Framework supports lazy loading of entities, in the next
section.

Lazy Loading:
One of the important functions of Entity Framework is lazy loading. Lazy
loading means delaying the loading of related data, until you specifically
request for it. For example, Student class contains StudentAddress as a
complex property. So, the context first loads all the students from the
database, then it will load the address of a particular student when we access
StudentAddress property as shown below.

using (var ctx = new SchoolDBEntities())


{
//Loading students only
IList<Student> studList = ctx.Students.ToList<Student>();
Student std = studList[0];
//Loads Student address for particular Student only (seperate SQL
query)
StudentAddress add = std.StudentAddress;
}

The code shown above will result in two SQL queries. First, it will fetch all
students:

SELECT
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],

[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]

The, it will send the following query when we get the reference of
StudentAddress:

exec sp_executesql N'SELECT


[Extent1].[StudentID] AS [StudentID],
[Extent1].[Address1] AS [Address1],
[Extent1].[Address2] AS [Address2],
[Extent1].[City] AS [City],
[Extent1].[State] AS [State]
FROM [dbo].[StudentAddress] AS [Extent1]
WHERE [Extent1].[StudentID] = @EntityKeyValue1',N'@EntityKeyValue1
int',@EntityKeyValue1=1

However, you can also turn off lazy loading for a particular property or an
entire context. To turn off lazy loading for a particular property, do not make
it virtual. To turn off lazy loading for all entities in the context, set its
configuration property to false:

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Core.Objects;
using System.Linq;
public partial class SchoolDBEntities : DbContext
{
public SchoolDBEntities(): base("name=SchoolDBEntities")
{
this.Configuration.LazyLoadingEnabled = false;
}

protected override void OnModelCreating(DbModelBuilder


modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
}

Rules for lazy loading:

1. context.Configuration.ProxyCreationEnabled should be true.


2. context.Configuration.LazyLoadingEnabled should be true.
3. Navigation property should be defined as public, virtual. Context
will NOT do lazy loading if the property is not defined as virtual.
Learn how to load entities explicitly in the next section.

Explicit Loading with DBContext


Even with lazy loading disabled, it is still possible to lazily load related
entities, but it must be done with an explicit call. Use the Load method of
DBEntityEntry object to accomplish this.
The following code explicitly loads Standard of particular Student using the
Reference() method of DbEntityEntry:

using (var context = new SchoolDBEntities())


{
//Disable Lazy loading
context.Configuration.LazyLoadingEnabled = false;
var student = (from s in context.Students
where s.StudentName == "Bill"
select s).FirstOrDefault<Student>();
context.Entry(student).Reference(s => s.Standard).Load();

}
If you run the code shown above, you can see that it first loads student but
not standard, as shown below:

The load method to get the Standard entity is shown below:

The code shown above will execute two different database queries. The first
query gets Student and the second query gets Standard.

Load collection:
Use the Collection() method instead of Reference() method to load collection
navigation property. The following example loads the courses of student.

using (var context = new SchoolDBEntities())


{
context.Configuration.LazyLoadingEnabled = false;
var student = (from s in context.Students
where s.StudentName == "Bill"
select s).FirstOrDefault<Student>();
context.Entry(student).Collection(s => s.Courses).Load();
}
Note: The Load extension method works just like ToList, except that it avoids
the creation of the list altogether.

Execute Native SQL Query


You can execute native raw SQL query against the database using
DBContext. You can execute the following types of queries:
1. SQL query for entity types which returns particular types of entities
2. SQL query for non-entity types which returns a primitive data type
3. Raw SQL commands to the database

SQL query for entity types:


As we have seen in one of the previous chapters, DBSet has SQLQuery()
method to write raw SQL queries which return entity instances. The returned
objects will be tracked by the context, just as they would be if they were
returned by a LINQ query. For example:

using (var ctx = new SchoolDBEntities())

var studentList = ctx.Students.SqlQuery("Select * from


Student").ToList<Student>();
}

However, columns returned by SQL query should match the property of an


entity type of DBSet otherwise, it will throw an exception. For example:

using (var ctx = new SchoolDBEntities())


{
var studentName = ctx.Students.SqlQuery("Select studentid,
studentname
from Student where studentname='New Student1'").ToList();
}

If you change the column name in query, then it will throw an exception
because it must match column names:

using (var ctx = new SchoolDBEntities())


{
//this will throw an exception
var studentName = ctx.Students.SqlQuery("Select studentid as id,
studentname as name
from Student where studentname='New Student1'").ToList();
}

SQL query for non-entity types:


A SQL query returning instances of any type, including primitive types, can
be created using the SqlQuery method on the Database class. For example:

using (var ctx = new SchoolDBEntities())


{
//Get student name of string type

string studentName = ctx.Database.SqlQuery<string>("Select


studentname
from Student where studentid=1").FirstOrDefault<string>();
}

Raw SQL commands to the database:


ExecuteSqlCommnad method is useful in sending non-query commands to
the database, such as the Insert, Update or Delete command. For example:

using (var ctx = new SchoolDBEntities())


{
//Update command
int noOfRowUpdated = ctx.Database.ExecuteSqlCommand("Update
student
set studentname ='changed student by command' where
studentid=1");
//Insert command
int noOfRowInserted = ctx.Database.ExecuteSqlCommand("insert into
student(studentname)
values('New Student')");
//Delete command
int noOfRowDeleted = ctx.Database.ExecuteSqlCommand("delete from
student
where studentid=1");
}

Validate Entity
You can write custom server side validation for any entity. To accomplish this,
override ValidateEntity method of DBContext as shown below.

protected override System.Data.Entity.Validation.DbEntityValidationResult


ValidateEntity(DbEntityEntry entityEntry,
System.Collections.Generic.IDictionary<object, object> items)
{
if (entityEntry.Entity is Student)
{
if (entityEntry.CurrentValues.GetValue<string>("StudentName") ==
"")
{
var list = new
List<System.Data.Entity.Validation.DbValidationError>();
list.Add(new
System.Data.Entity.Validation.DbValidationError("StudentName",
"StudentName is required"));
return new
System.Data.Entity.Validation.DbEntityValidationResult(entityEntry, list);
}
}
return base.ValidateEntity(entityEntry, items);
}

As you can see in the above code, we are validating the Student entity. If
StudentName is blank, then we are adding DBValidationError into
DBEntityValidationResult. So whenever you call DBContext.SaveChanges
method and you try to save Student entity without StudentName, then it will
throw DbEntityValidationException. For example:

try
{
using (var ctx = new SchoolDBEntities())
{
ctx.Students.Add(new Student() { StudentName = "" });
ctx.Standards.Add(new Standard() { StandardName = "" });

ctx.SaveChanges();
}
}
catch (DbEntityValidationException dbEx)
{
foreach (DbEntityValidationResult entityErr in
dbEx.EntityValidationErrors)
{
foreach (DbValidationError error in entityErr.ValidationErrors)
{
Console.WriteLine("Error Property Name {0} : Error Message:
{1}",
error.PropertyName, error.ErrorMessage);
}
}
}

Multiple Diagrams in Entity Framework


5.0
Visual Studio 2012 provides a facility to split the design time visual
representation of the Entity Data Model. This means that you can have
multiple diagrams for one Entity Data Model.
You can create a new diagram in multiple ways:
1. Add a new diagram and drag and drop entities from Model Browser
2. Move entities from an existing diagram to a new diagram

1. Add a new diagram and drag and drop entities


from Model Browser:
You can add a new diagram by right clicking on the Diagrams node of the
model browser and selecting 'Add New Diagram':

You can rename the diagram, for example: StudentDiagram to include all
student related entities:

Now, you can drag and drop Student and StudentAddress entities to this new
diagram:

2. Move entities from existing diagram to new


diagram:
You can also move entities from an existing diagram to a new diagram. For
example, if you want to move Teacher and Course entities to a new diagram,
then select those entities in an existing diagram and right click and select
'Move to New Diagram' from the context menu:

It will create a new diagram and move Teacher and Course entities to a new
diagram as shown below:

So, in this way you can create a new diagram from an existing diagram.
You can also include the related entities of a particular entity. For example,
right click on Student entity select 'Include Related'. Standard and Course
entities will also be included, because Student has their reference property:

This will include Standard and Course entity as shown below.

Additionally, you can also move properties up or down by right clicking on the
property select Move Property select UP/Down etc. as shown below:

Difference between delete and remove entity:


You can remove the entity from the diagram by right clicking on entity and
selecting 'Remove from diagram'.

Remove from Diagram will only remove the entity from the diagram whereas
'Delete from Model' will delete the entity from the EDM. So you won't be able
to use that entity at all.

Colored Entity in Entity Framework 5.0


You can change the color of an entity in the designer so that it would be easy
to see related groups of entities in the designer from Visual Studio 2012
onwards. To change the color of an entity, select entity in the designer go
to property window (press F4) change the Fill Color property. For example:

To change the color of multiple entities at once, select multiple entities and
change Fill Color from the property window:
Additionally, you can also change the property format of entities to either
Display name or Display name and type. Right click on designer select
'Scalar Property format' select 'Display Name and Type':

Properties will be displayed with its type as shown below:

This way, you can change the color and display of entities in the EDM
designer.

You might also like