What Is Entity Framework
What Is Entity Framework
What Is Entity Framework
Now the question is what is O/RM framework and why do we need it?
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 maps to relational database
objects (tables, views & storedprocedures). ORM helps us to keep our database design separate from our
domain class design. This makes application maintainable and extendable. It also automates standard
CRUD operation (Create, Read, Update & Delete) so developer doesnt need to write it manually.
There are many ORM frameworks for .net in the market like DataObjects.Net, NHibernate, OpenAccess,
SubSonic etc. Entity Framework is an open source ORM framework from Microsoft.
Page | 2
EDM (Entity Data Model): EDM consist three main parts- Conceptual model, Mapping and Storage
model.
Conceptual Model: Conceptual model is your model classes and their relationships. This will be
independent from your database table design.
Storage Model: Storage model is your database design model which includes tables, views, stored
procedures and their relationships and keys.
Mapping: Mapping consist information about how your conceptual model is mapped to storage model.
LINQ to Entities:LINQ to Entities is 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 again a query language same as LINQ to Entities. However it is little more
difficult than L2E and also developer need to learn it separately.
Page | 3
Object Service:Object service is a main entry point for accessing data from database and to return it
back. Object service is responsible for materialization which is process of converting data returned from
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 SQL query which is understood by underlying database. It communicates with ADO.Net data
provider which in turn sends or retrieves data from database.
ADO.Net Data Provider:This layer communicates with database using standard ADO.Net.
This tutorial will use sample SchoolDB which has different tables, stored procedures and view.
Page | 4
Sample project contains SchoolDB.mdf which you can attach to your local SQL server 2005 database.
Page | 5
Here, we are going to create Entity Data Model (EDM) for SchoolDB database and understand basic
building blocks.
You can create entity data model for existing database in Entity Framework 5.0 the same way as you
created it in Entity Framework 4.1/4.3.
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 Name School and click Add
button.
Page | 6
3. Entity Data Model Wizard in VS2012 opens with four options to select. EF Designer from database is
for database first approach, Empty EF Designer model for model first approach, Empty Code First
model and Code First from database is for code first approach. We will focus of database first approach
in the basic tutorials so select EF Designer from database option and click Next
Page | 7
4. You can choose from your existing DB Connections or create new connection by clicking New
Connection button. I use existing db connection to my SchoolDB Database. This will also add connection
string to your app.config file with default suffix with db name. You can change it if you want. Click
Next after you set up your db connection.
Page | 8
5. In this step, you need to choose the version of Entity Framework. We will use Entity Framework 5.0 in
the basic tutorials so select Entity Framework 5.0 and click Next.
Page | 9
6. This step will display all the Tables, Views and Stored Procedures in the database. Select 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 singularize entityset name if table name in
the database is plural eg. If SchoolDB has Students table name then entityset would be singular Student.
Similarly relationships between the model will be pluralize if table has one-to-many or many-to-many
relationship with other table. Eg. Student has many-to-many relationship with course table so Student
entity set will have plural property name 'Courses' for the collection of courses.
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 Standard property but not StandardId in Student entityset.
Third checkbox, Import selected stored procedures and functions into entity model automatically
creates Function Imports for the stored procedures and functions. You dont need to manyally import it as
you had to do it prior to Entity Framework 5.0.
P a g e | 10
7. After clicking on Finish, it will add School.edmx file into your project.
Open EDM designer by double clicking on School.edmx that displays all the entities for selected tables
and relation between them as below:
P a g e | 11
So this way you can create simple EDM from your existing database.
Now lets see all the building blocks of generated EDM (School.edmx) as shown in above figure.
Entity-Table Mapping:
Each entity in EDM is mapped with database table. You can check entity-table mapping by right click on
any entity in the EDM designer -> select Table Mapping. Also, if you change any property name of entity
from designer then table mapping would reflect that automatically.
P a g e | 12
Every Entity Data Model generates one context class and multiple entity classes for each DB table.
Expand School.edmx and see two important files, {EDM Name}.Context.tt and {EDM Name}.tt:
P a g e | 13
School.Context.tt: This T4 template file generates context class whenever you change Entity Data Model
(.edmx file). You can see context class file by expanding School.Context.tt. Context class resides in
{EDM Name}.context.cs file. Default context class name is {DB Name} + Entities eg. Context class
name for our SchoolDB is SchoolDBEntities. Context class is derived from DBContext class in Entity
Framework 5.0. Prior to EF 5.0, it used to derive from ObjectContext.
P a g e | 14
School.tt: School.tt is T4 template file that generates entity classes for each DB tables. Entity classes are
POCO (Plain Old CLR Object) classes that can be proxy classes (we will see later what is proxy classes).
EDM Designer: EDM designer represents your conceptual model. It consist Entities, associations &
multiplicity between the entities. Initially it will exactly look like your database table structure but you
can add or merge columns or remove columns which are not required by your application from this
designer. Even you can add new object in this model which can have columns from different database
tables from context menu as shown in above figure. Remember, whatever changes you do here it should
be mapped with storage model. So you have to be careful while doing any changes in the designer.
You can open this EDM designer in XML view where you can see all the three part of EDM- Conceptual
schema (CSDL), Storage schema (SSDL) and mapping schema (MSL), together in XML view.
P a g e | 15
Right click on School.edmx -> click Open with.., this will open popup. Select XML (text) Editor in the
popup. Visual Studio cannot display the model in Design view and in XML 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
XML view. You can see following XML view by toggling all outlining
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 dont need to edit xml
because you can do it in the Model Browser.
Model Browser: Open Model Browser by right clicking on the EDM Designer and select Model Browser
from context menu:
Model browser contains all the information about the EDM, its conceptual model, storage model and
mapping information.
P a g e | 16
EntityContainer EntityContainer is a wrapper for EntitySets and AssociationSets. It is critical entry point
for querying the model.
EntitySet: EntitySet is a container for EntityType. It is set of same entitytype. You can think it like db
table.
P a g e | 17
EntityType: EntityType is a datatype in the model. You can see each EntityType for your conceptual
model in XML. If you expand EntityType node in XML, you can see each properties and its type and
other info.
Entity Framework 5.0 is limited to POCO entity and Dynamic proxy entity. EntityObject used to use with
ObjectContext which is not being used in Entity Framework 5.0. Also, it is not recommended to use selftracking entities.
POCO (Plain Old CLR Object): POCO class is the class that doesnt depends on any framework
specific base class. It is like any other normal .net class that 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. Eg. Following is
a Student POCO class.
public class Student
{
public int StudentID { get; set; }
public string StudentName{ get; set; }
public Standard Standard{ get ; set; }
public StudentAddress StudentAddress{ get ; set; }
public IList<Course> Courses{ get; set; }
}
Dynamic Proxy is a runtime proxy class of POCO entity. POCO entity becomes POCO Proxy entity if it
meets the certain requirements to enable lazy loading and automatic change tracking. It adds some
methods at runtime to your POCO class which does instant change tracking and lazy loading stuff.
P a g e | 18
POCO entity should meet the following requirement to become POCO proxy:
1. A custom data class must be declared with public access.
2. A custom data class must not be sealed (NotInheritable in Visual Basic)
3. A custom data class must not be abstract (MustInherit in Visual Basic).
4. ProxyCreationEnabled option should not set to false (default is true) in context class
5. Each navigation property must be declared as public, virtual
Note: By default dynamic proxy is enabled for every entity. However, you can disable dynamic proxy by
setting ProxyCreationEnabled option to false in context class.
context.Configuration.ProxyCreationEnabled = false;
EDM generates POCO entities which satisfy above requirement of dynamic proxy by default.
P a g e | 19
You can use ObjectContext.GetObjectType() to find actual type of dynamic proxy as below:
Entity can have two types of properties, Scalar properties and Navigation properties.
Scalar properties are properties whose actual values are contained in the entity. For example, Student
entity has scalar properties e.g. StudentId, StudentName. These corresponds with the Student table
columns.
Navigation properties are pointers to other related entities. The Student has Standard property as
navigation property that will enable application to navigate from a Student to related Standard entity.
1) LINQ to Entities: L2E query syntax is easier to learn than Entity SQL. You can use your LINQ skills
for querying with EDM. There are two types of syntax you can use with LINQ-to-Entities, LINQ Method
Syntax with Lamda expression and LINQ query syntax.
P a g e | 20
//Querying with LINQ to Entities
using (var context = new SchoolDBEntities())
{
var L2EQuery = context.Students.where(s => s.StudentName == Bill);
}
First, you have to create object of context class which is SchoolDBEntities. You should initialize it in
using() so that once it going out of using scope then it will automatically call Dispose() method of
DbContext. In both the syntax above, context returns IQueryable.
We will learn different types of LINQ to Entities query in projection query chapter later.
2) 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.
Following code snippet shows 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 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>();
P a g e | 21
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);
}
}
}
3) Native SQL You can execute native SQL query for relational database as below:
using (var ctx = new SchoolDBEntities())
{
var studentName = ctx.Students.SqlQuery("Select studentid, studentname,
standardId from Student where studentname='Bill'").FirstOrDefault<Student>();
}
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 classes first and then generating the database required to persist their data.
P a g e | 22
You can create entity, association and inheritance on empty designer using toolbox.
P a g e | 23
After creating required entities, associations and inheritance on design surface of the empty model, you
can use designers context menu option 'Generate database from model' to generate DDL script.
Select existing database connection from wizard and then it will display DDL for the entities.
P a g e | 24
P a g e | 25
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 Include method of IQueryable.
Below code snippet shows eager loading where Standard entity will also be loaded with Student entity
using Include method:
P a g e | 26
You can also eagerly load multiple levels of related entities. Below code snippet loads related Student,
Standard and Teachers:
using (var ctx = new SchoolDBEntities())
{
stud = ctx.Students.Where(s => s.StudentName == "Student1")
.Include(s => s.Standard.Teachers).FirstOrDefault<Student>();
}
Lazy Loading:
One of the important functionality of Entity Framework is lazy loading. Lazy loading means delaying the
loading of related data until you specifically request it. For example, Student class contains
StudentAddress as complex property. So context first loads all the students from the database then it will
load address of particular student when we access StudentAddress property as below.
P a g e | 27
using (var ctx = new SchoolDBEntities())
{
ctx.Configuration.LazyLoadingEnabled = true;
//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;
}
Above code will result in two SQL query. First, it will fetch all students:
SELECT
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
And then sends 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 particular property or entire context. To turn off lazy
loading for particular property, do not make it virtual. To turn off lazy loading for all entities in the
context, set its configuration property to false:
public SchoolDBEntities(): base("name=SchoolDBEntities")
{
this.Configuration.LazyLoadingEnabled = false;
}
P a g e | 28
3. Complex property should be defined as virtual. Context will not do lazy loading if the property is
not define as virtual.
Following code explicitly loads Standard of particular Student using 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.Courses).Load();
}
If you run above code, you can see that first it loads student but not standard as below:
P a g e | 29
Above code execute two different database queries. First query is to get Student and second query to get
standard.
Load collection:
Use collection method instead of Reference method to load collection navigation property. Following
example loads 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.
P a g e | 30
DBContext:
As you have seen in previous chapter, EDM generates Context class and Entity classes. This context class
is derived from System.Data.Entity.DbContext class.
DbContext is a primary class that is responsible for interacting with data as object. It often referred to as
context. It does following activities:
Querying: It can be useful in querying the database. It converts database values into entity
objects and vica versa.
Change Tracking: It keeps track of changes occurred in the entities after it has been querying
from the database.
Persisting Data: It also perform Insert, update and delete operation to the database based on the
entity states.
Prior to EntityFramework 4.1, EDM used to generate context class that derived from ObjectContext class.
It was little tricky to work with ObjectContext. DbContext is conceptually similar to ObjectContext. It is
a wrapper around ObjectContext which is useful in all development models: Code First, Model First and
Database First.
DBContext API is easier to use than ObjectContext API for all common tasks. However, you can get
reference of ObjectContext from DBContext to use some of the features of ObjectContext by using
IObjectContextAdpter as below:
using (var ctx = new SchoolDBEntities())
{
var objectContext = (ctx as IObjectContextAdapter).ObjectContext;
//use objectContext now
}
See what are the important methods and properties of DbContext class in the next chapter.
DBContext Class
DBContext represents a combination of the Unit-Of-Work and Repository patterns and enables you to
query a database and group together changes that will then be written back to the store as a unit.
P a g e | 31
Public Methods:
Method
Name
Return Type
Description
Example
DBSet
Returns a
DbSet for the
specified type,
this allows
CRUD
operations to
be performed
for the given
entity in the
context.
CRUD operation.
ctx.Set(stud.GetType().BaseType).Add(studentEn
tity);
ctx.Set(stud.GetType().BaseType).Attach(student
Entity);
ctx.Set(stud.GetType().BaseType).Remove(stude
ntEntity);
var result =
ctx.Set(studentEntity.GetType().BaseType).SqlQu
ery("select * from student");
studentEntity.GetType() will return POCO Proxy
type.
studentEntity.GetType().BaseType should be use
to get an actual entity type.
P a g e | 32
Set<TEntity DBSet
>()
Returns a
DbSet for the
specified type,
this allows
CRUD
operations to
be performed
for the given
entity in the
context.
SaveChang int
es()
CRUD operation.
dbcontext.Set<Student>().Add(studentEntity);
dbcontext.Set<Student>().Attach(studentEntity)
;
dbcontext.Set<Student>().Remove(studentEntit
y);
var result = dbcontext.Set().SqlQuery("select *
from student");
Saves all
Save changes to the database:
changes made
in this context Dbcontext.SaveChanges();
to the
underlying
database.
Protected Methods:
Method Name
Return Type
ShouldValidateE bool
ntity
ValidateEntity
Description
Extension point allowing the user to override the
default behavior of validating only added and
modified entities.
Public Properties:
Property
Name
Return Type
ChangeTrac DBChangeTracker
ker
Description
Provides access to features of the context that deal with
change tracking of entities.
Database
P a g e | 33
Connected Scenario: Connected scenario is when an entity is retrieved from the database and persist
using same context. Context object doesnt destroy between when entity retrival and persistence.
P a g e | 34
CRUD operation in connected scenario is fairly easy task because context automatically detact changes
happened in the entity provided AutoDetectChangesEnabled is true by default.
Following example show how you can add, update and delete entity using context and call
context.SaveChanges() method to update the database.
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();
}
P a g e | 35
Note: If AutoDetectChangesEnabled is set to 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 edited entities and mark their status Modified.
Context detects adding and deleting entity when performed only on DbSet. If you perform add and delete
entity on separate collection or list then it wont detect these changes.
Following code will NOT insert or delete student. It will only do update student:
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();
}
Following statement attach entity into context and mark its state to Modified:
dbCtx.Entry(Entity).State = System.Data.EntityState.Modified;
P a g e | 36
Student stud ;
// Get student from DB
using (var ctx = new SchoolDBEntities())
{
stud = ctx.Students.Where(s => s.StudentName == "New
Student1").FirstOrDefault<Student>();
}
// change student name in disconnected mode (out of DBContext scope)
if (stud != null)
{
stud.StudentName = "Updated Student1";
}
//save modified entity using new DBContext
using (var dbCtx = new SchoolDBEntities())
{
//Mark entity as modified
dbCtx.Entry(stud).State = System.Data.EntityState.Modified;
dbCtx.SaveChanges();
}
As you see in the above code snippet, we are doing following steps:
1. Get the existing student
2. Change student name out of DBContext scope (disconnected mode)
3. We pass modified entity into Entry method to get its DBEntityEntry object and then marking its
state as Modified
4. Calling SaveChanges to update student information into the database.
SaveChanges will send 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 the next chapter we will learn how to update an one-to-one relationship entities.
P a g e | 37
As you can see in above code snippet, first we have created new Standard entity object and set
StandardName to 'Standard 1'. Second, created new DBContext object and added newly created Standard
entity into Standards EntitySet. Third, calling SaveChanges method of DBContext which sends insert
query to the database.
Alternatively, we can also add Standard entity into DBContext.Entry and mark it as Added which result in
same insert query:
dbCtx.Entry(newStandard).State = System.Data.EntityState.Added;
In the next chapter we will learn how to add entities which has one-to-one relationship.
P a g e | 38
using (var context = new SchoolDBEntities())
{
context.Entry(disconnectedTeacher).State = System.Data.EntityState.Deleted;
context.SaveChanges();
}
Above code results in following delete query which deletes the row from Teacher table.
delete [dbo].[Teacher]
where ([TeacherId] = @0)',N'@0 int',@0=1
Let's see how you can handle optimistic concurrency with Student entity.
First of all, you need to have rowversion column in the Student table In order to handle concurrency with
Stuent entity. Rowversion is is a datatype in SQL Server that automatically generates unique binary
number whenever insert or update operation performed in a table. The rowversion datatype is just an
incrementing number. Rowevesion is synonym for the timestamp datatype. Both are same.
Create new column RowVersion in Student table with timestamp datatype as below:
P a g e | 39
Note: Value of RowVersion will be added and updated automatically by the databse in Insert and
Updateoperation.
Now, create new Entity Data Model or update an existing data model by right clicking on designer ->
Update Model From Database -> Refresh Student table. So now, you will see RowVersion property
added in the Student entity.
Now, you need to apply 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 below:
EF will now include RowVersion column in the where clause whenever you do update operation and if
rowversion value is different than in where clause then it will throw DbUpdateConcurrencyExection.
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;
P a g e | 40
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";
now, User1 saves his changes before User2. So when user2 trys 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 timestamp property in code-first by usng [Timestamp] attribute. Make sure property type
is byte[] because timestamp is binary in C#.
[Timestamp]
public byte[] RowVersion { get; set; }
P a g e | 41
EF includes property in where clause in update operation if the property is marked withTimestamp
attribute.
You can resolve concurrency exection many ways. Visit msdn on detailed information on how to resolve
optimistic concurrency.
Entity Framework 6.0 has introduced many new exciting features for database first (designer) and codefirst approaches.
P a g e | 42
11. Creating context with an open connection
12. Improved performance and warm-up time
Lets see how to execute asynchronous query first and then we will see asynchronous call to
context.SaveChanges.
Asynchronous Query:
private static async Task<Student> GetStudent()
{
Student student = null;
using (var context = new SchoolDBEntities())
{
Console.WriteLine("Start GetStudent...");
student = await (context.Students.Where(s => s.StudentID ==
1).FirstOrDefaultAsync<Student>());
P a g e | 43
Console.WriteLine("Finished GetStudent...");
}
return student;
}
As you can see in the above code, GetStudent method marked with async to make it asynchronous.
Return type of asynchrounous method must be Task. GetStudent returns object of Student entity so return
type must be Task<Student>.
Also, query is marked with await, this freed calling thread to do something else till it executes query and
returns data. We have used FirstOrDefaultAsync extension method of System.Data.Entity. you may use
other extension methods appropriately like SingleOrDefaultAsync, ToListAsyn etc.
Asynchronous Save:
You can call context.SaveChanges asynchronously the same way as async query:
Transaction support:
Entity Framework by default wraps Insert, Update or Delete operation in a transaction whenever you
execute SaveChanges(). EF starts new transaction for each operations and complete the transaction when
it operation finishes. When you execute another such operation a new transaction is started.
P a g e | 44
dbTran.Commit();
}
catch (Exception ex)
{
//Rollback transaction if exception occurs
dbTran.Rollback();
}
}
database.UseTransaction allows the DbContext to use a transaction which was started outside of the
Entity Framework.
There are two main types of Conventions, Configuration Conventions and Model Conventions.
Configuration Conventions:
P a g e | 45
Configuration Conventions are a way to configure entities without overriding default behaviour provided
in the Fluent API. You can define a configuration convention inside your OnModelCreating event or in a
custom Convention Class in a similar way to how you would define normal entity mappings with the
Fluent API.
For example, you can define primary key of entity that has property named {entity name} _ID. E.g.
Student_ID property of Student entity will be primary key:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Properties()
.Where(p => p.Name == p.DeclaringType.Name + "_ID")
.Configure(p => p.IsKey());
base.OnModelCreating(modelBuilder);
}
Following example show how to set string length of Description property in all entities:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Properties()
.Where(p => p.Name == "Description")
.Configure(p => p.HasMaxLength(200));
base.OnModelCreating(modelBuilder);
}
You can also define custom class for this convention by deriving Convention class as below:
public class PKConvention : Convention
{
public PKConvention()
{
.Properties()
.Where(p => p.Name == p.DeclaringType.Name + "_ID")
.Configure(p => p.IsKey());
}
}
Model Conventions:
P a g e | 46
Model Conventions is based on the underlying model metadata. There are conventions for CSDL and
SSDL both. Create class that implements IConceptualModelConvention form CSDL conventions and
implement IStoreModelConvention for SSDL convention.
Student Entity:
class Student
{
public Student()
{
}
public int Student_ID { get; set; }
public string StudentName { get; set; }
}
Following example automatically create stored procedure for Student entity using Fluent API.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.MapToStoredProcedures();
}
Above code will create three procedures Student_Insert, Student_Update and Student_Delete.
Student_Insert and Student_Update stored procedures has parameters name corresponds to the property
names. Student_Delete will have primary key property StudentID parameter.
P a g e | 47
You can also change stored procedure and parameters name as below:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.MapToStoredProcedures(p => p.Insert(sp =>
sp.HasName("sp_InsertStudent").Parameter(pm => pm.StudentName, "name").Result(rs =>
rs.Student_ID, "Student_ID"))
.Update(sp => sp.HasName("sp_UpdateStudent").Parameter(pm =>
pm.StudentName, "name"))
.Delete(sp => sp.HasName("sp_DeleteStudent").Parameter(pm =>
pm.Student_ID, "Id"))
);
}
If you want all your entities to use stored procedures then do as following:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Types().Configure(t => t.MapToStoredProcedures());
}
Limitations:
Only Fluent API can be used to map stored procedures. You cannot use Data Annotation attributes
in EF 6 for stored procedure mapping.
You cannot use mixture of stored procedure and query to add, update and delete operation on the
same entity. You can either use stored procedure or SQL query for all add, update and delete
operation with entity.
Previous
Next
Index Attribute:
P a g e | 48
Entity Framework 6 provides Index attribute to create Index on particular column in the database as
below:
class Student
{
public Student()
{
}
public int Student_ID { get; set; }
public string StudentName { get; set; }
[Index]
public int RegistrationNumber { get; set; }
}
By default, Index name will be IX_{property name}. However, you can also change Index name.
You can also make it Clustered index by specifying IsClustered = true and unique index by specifying
IsUnique=true.
[Index( "INDEX_REGNUM", IsClustered=true, IsUnique=true )]
public int RegistrationNumber { get; set; }