Entity Framework Code First

flutheronioneyedΛογισμικό & κατασκευή λογ/κού

13 Δεκ 2013 (πριν από 4 χρόνια και 5 μήνες)

97 εμφανίσεις

Entity Framework Code First

After finding out what a client needs
an application, one of the first things I would do is design the database. Then as
the project progressed and I was writing code, I would find that I needed to change the database. In
addition to making
the db changes, I would have to change the code in various places that accessed the database. I always thought it would
be great if some of this disconnect between the code an
d the database could be reduced and I could just write code
thout having to open SSMS and change the database schema.

I recently started on a project that used the Entity Framework using the ‘Code First’ approach. In this approach, I didn’t
have to worry about where or how the data was being stored. When I made cha
nges to the code, changes were
propagated to the database.

While some parts of it were very easy and happened automatically, there are some areas that can be troublesome for
newbies. This presentation will be an overview on using ‘Entity Framework Code Fir
st’ and will show you
how you can
define your model objects by writing some pocos. It will also cover
some of the areas to watch out for and lessons I have
learned…sometimes the hard way. In addition to the basics, if time allows, we will
show how the Enti
ty Framework
works seamlessly with MVC and
go into
some more advanced topics.

Creating Code First Demo Project

Create new application library

Add Entity Framework Nuget package

Add an employee class

and make it public

Add a company class

and make
it public

Create a context class derived from dbcontext

and make it public
. You will need to add System.Data.Entity namespace
to class

Add the DbSets for company and employee

Use EF package in project by selecting manage nugget packages for solutio

Build CodeFirstDemo1

Add reference to the Code First project.

Set the project as the startup project.

Initialize the context and add a record

What will happen when I run the app now? I haven’t done anything to configure a database.

successfully runs, so let’s go see what happened and where the data went. In localdb, you can see that a database was
created and the 2 tables added.

It ended up here in localdb because I didn’t set up anything in the config or
programmed against the fluen
tdb api.

Notice that it created the PK from the columns named Id. You could also have used the convention of tablenameid and it
would have used that for the PK.

Notice the configuration history table that was created and look at the record.

Configuring DB Initialization

We can configure both where to look for and create the database as well as the initialization strategy to be used.

pecify where you want the database

Specify the name of a database in the context constructor and if it doesn’
t exist in the localdb, it will be created. Edit the
constructor of the Context class to have a new database name.

By default, it will use the localdb if you haven’t specified otherwise in a connections string. If you didn’t want it to crea
a dat
abase on localdb, you can create a connection string in app.config specifying where you want it to go and then in
the Context, specify the connection string that should be used when the initializer runs.

To see this this, you can add the following to your
app.config for the console app.




Data Source=samsung
Catalog=TestInitializingWithNamedConnectionsString;Integrated Security=true



Then in Context.cs, add ‘MainConnectionString’ as a parameter to the base constructor as shown below.

After running the app, you can see that it created a database under my SQLExpress2012 instance

Command Injection

Before we set an initialization strategy, let’s create a way to see what the EF API is doing under the covers for us. We
need a way to intercept the commands being sent to the database and log them to the console for us to watch.

First, w
e need to add a logging framework. Since I like nLog as a free open source logging provider, I am going to add it
to the project using Nuget.

Add nlog

info to

configuration fle.

Add the interceptor code.

Add the call to start the interceptor to the
sub m
ain and add a breakpoint on that call. Then press F5.

Step through the code to see when something happens at the db level.

When you get to the point sahown in the image below, you should have a number of things logged to the console.

Below is some of
what is displayed on the console.

As you can see, it is checking for the tables being present and is also reading the _migrationHistory table.

Now we’ll change the name of the database
in the initializer
and see what happens.

When it didn’t find the da
tabase, you can see that it went ahead and created it along with the tables.

Initialization Strategies

The first time the program runs, you want it to create the database for you. What do you want it to do on the second
and subsequent times? You have 4 opt
ions that you can specify to determine this behavior. They are:



this is the default. If you change the model with this initializer set, you will get an






DB Initializer

you specify whatever logic you want to use.

Let’s change the model and verify what happens.

As expected, we get an exception.

Set a DBInitializer in the
class to

as shown below.

Now when we run
the database is updated. If you put a break point and look at it, you would see it drop and then
create the database.

I’ll leave it to you to verify that if we set the initializer to

that it will drop and recreate the
every time, even if the model doesn’t change.

Seeding Your Data

If you choose one of the options that recreates your database, you may want your database to be seeded with some
data prior to running. To do that, you would add the data that you want inser
ted into your database into the Context.cs

Change the
Context.cs to use the DemoI

Run it and watch to see that the database gets dropped and recreated and the data gets added.

Choosing an Initialization Strategy

When you are early in a

project and making a lot of changes to your model, you may want to choose one of the options
that includes dropping and recreating the database. Eventually, you will get to a point in the project where you will want
to control if and when the database get
s dropped and recreated.

When that is the case you will want to set the Context to use the CreateDatabaseIfNotExists initializer. In order to see
what happens, change the model and watch it blow up when run.

The error message is telling you that you
need to
do migrations to get the model changes made to the database.

Adding a Migration and Updating the Database

Open the Nuget Package Manager Console

Enter “add
” and type the name that you want for the migration. I usually use a long name des
criptive of what
the migration is for. For example, in the above change to the model, I added a DateOfBirth property to the employee
class. I would add a migration by typing something like “add
migration AddDateOfBirthToEmployee”.

In this case,
migrations have not yet been enabled for this project, so we need to do as it says and enable migrations.
When we do that, we get another error as shown below.

This confused me the first time I saw it, because I had been doing migrations on a project and

then it stopped working.
Somehow the default project changed from the one I was doing the migrations on. So if you change the default project
to CodeFirstDemoConsole, it will work.

This error tells us that since we want to use explicit migrations tha
t we need to delete the previously created automatic
migrations. So delete the initialcreate migration and rerun the add

Now run an add
migration and an update
database to get everything back in synch.

The migration created a file that has som
e instructions for both upgrading and downgrading a database. It is cool the
way that you can get your database to any
version of the app that you want. This only takes care of the situation where
you don’t have data. When you have data involved, you will
need to write your own code to transform the data

Now the app should run

Rolling Back

At the PM console type in


We are going to attempt to roll back to the
original database before code migrations were
enabled. As you can see below, this failed because we added data to the
database and it doesn’t want you accidentally blowing away your data.

In this case in order to force the update despite the data loss, we need to add a


What will ha
ppen if we run the app now?

We’ll get an exception because the DB does not match our code. In this case, there is an empty db.

If you get frustrated about going around in circles with error messages, you can always delete the db and let it create it
Once you have rolled back, you will want to delete any pending migrations. They will automatically get removed
from the _migration history table, but you will need to remove the migration files. Note that you can’t remove the
migration files before
the rollback because the migration file must run to undo the changes it had made to the database.

Following is the new migration file that gets created when I run a new add
migration from the PM prompt.

Run an update
database to get the database updated.

Looking at the db we see the expected schema and a record in the _

Configure Relationships

(Goto PPT)

One to zero or one

Create a new model class named EmployeeAddress and create a 1 to 0 or 1 relationship
. Add the entity to the

In the Employee class, add a property for the EmployeeAddress

At PM enter “add
migration” and you get the following result. Since we do not have a
property named Id or
EntityNameId, it has no way to determine what should be the primary key.

We can help entity framework out by specifying that the EmployeeId is both the primary key and the foreign key. We
will get more into data annotations in a minute.

At the PM run add
migration again and then

when that completes type “update
. It s
hould complete

Look at the database

Configure One to Many Relationship

We’ll create a one to many relationship between a company and their employees. To do this, we’ll add a property to the
Company class hold a list of employees and on the
constructor we will need to initialize that list.

migration, update
database and then look at db.

Configuring a Many
Many Relationship

Suppose you also wanted to be able to discern when your employees work at multiple companies. In that case,
we will
need a many to many relationship.

Edit the Employee.cs so that
it can hold a collection of Companies and that the list gets initialized in constructor.

In prep, when going from a one
many to a many
many, EF got confused, so I rolled back to a
n earlier point using

TargetMigration:, deleted the 2 migrations in between, and then did an add
migration and then an

and look at db.

Data Annotations

(Goto PPT)

Validation Attributes:




The Required annotation will force EF (and MVC) to ensure that property has data in it.


MinLength annotation validates property whether it has minimum length of array or string.


MaxLength annotation maximum
length of property which in
tern set maximum length of
column in the database


Specifies the minimum and maximum length of characters that are allowed in a data field.

Database Schema related Attributes:




Specify name of the DB table which will be mapped with the class


Specify column name and datatype which will be mapped with the property


Mark property as EntityKey which will be mapped to PK of related table.


Mark the class
as complex type in EF.


Mark the property as a non
nullable timestamp column in the database.


Specify Foreign key property for Navigation property


Specify that property will not be mapped with database


ConcurrencyCheck annotation allows you to flag one or more properties to be used for
concurrency checking in the database when a user edits or deletes an entity.


DatabaseGenerated attribute specifies that property will be mapped to
Computed column of
the database table. So the property will be read
only property. It can also be used to map the
property to identity column (auto incremental column).


InverseProperty is useful when you have multiple relationship between
two classes.

Add a few attributes, add
migration and update

Look at database and note that name is now required and it is set as nvarchar(200)