Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Simple Demo Entity Framework - the beast unleashed

4.96/5 (29 votes)
15 Nov 2015CPOL40 min read 40.3K   1K  
Simple Demo Entity Framework - a tutorial explaining Code First!

Content

  1. Introduction 
  2. Entity Framework Introduction 
  3. Code First Driven Approach 
  4. The Project that we will be Developing 
  5. The Project - Quick Look at the Domain Classes 
  6. Creating DbContext Class  
  7. Interacting With the DataBase 
  8. Explaining the Database created by Code First
  9. Lets understand CodeFirst Migrations
  10. Interacting with Database - Inserting records in Discussion Database
  11. Interacting with Database - Updating and Querying Discussion Database
  12. Interacting with Database - Deleting Records in Discussion Database 
  13. Interacting with Database - Retrieving Graphs of Data Records from Discussion Database
  14. Final Thoughts

 Introduction

In this article we will be looking into understanding a Entity Framework 6. especially the Code First Approach.

About EF 6

"Entity Framework" basically comes in 3 flavours:

  1. Database First
  2. Model First
  3. and lastly, the jewel in the EF crown...Code First - the one we will be covering in this article

The goal is to demonstrate every aspect of EF 6 Code First that I can recall. Rest assured I will try my best to cover every detail so as to make your journey along this article as comfortable as possible.

Hopefully, we will learn to appreciate Microsoft a little more than we do now once we are done here :)

On a side note - I have written a couple of articles regarding WCF web services, please feel free to explore them at your convenience.

  1. Simple Demo - WCF Web Services Article (SOAP Service)
  2. Simple Demo - WCF AJAX Services Article
  3. Simple Demo - WCF RESTful Web Services Article

I will be following the KISS concept: "Keep it Simple Stupid."

So lets get the ball rolling...

Before you proceed, assumption is that: you have Visual Studio 2013 (or prior version) and SQL Server 2012 installed, configured and working in complete harmony. If not it would be a good time to google for Visual Studio Community Edition to start with.

Entity Framework Introduction

Overview

Entity Framework is an Object Relational Mapper ("ORM"). ORM provides benefits including improved Developer Productivity (EF takes good care of pulling and feeding data to Databases) - EF can produce basic commands for reading and writing data to databases thus improving life's of many developers.

The queries are written using the Domain Objects you have declared in you app using something called " LINQ to Entities " and the retrieved results from the database are automatically converted into the Domain objects that we have defined in our software app. Basically, life becomes a lot more easier.

In theory, ORM like Entity Framework let's us focus more on the business side of things rather than worrying about the database too much. In EF we focus on something called the Conceptual Model (of your domain)
Now this is a Model of OBJECTS in your application and NOT the model of your database that you use to persist your applications data.

Now here is the kicker, depending on cases we might have a Conceptual Model that aligns with our database model and on the other hand we can also end up having an conceptual model that does not aligns with our database model.

Yes EF is that flexible. and easy going.

Once, we have our Conceptual Model we can than use a feature of Entity Framework that is called Code First than can create the database tables among other things for us in the database of our choosing.

The bigger picture is Entity Framework is able to map between our conceptual model and the database of what it needs to do when it comes to persisting data with ease-of-use and elegance. So we write queries against our Conceptual Model and Entity Framework makes sure to compose the necessary queries to read/write and update data in database.

How EF does what it does you ask?

You write your queries with LINQ to Entities - Entity Framework breaks them down into Command Trees then the provider transforms these Command Trees into appropriate sequel queries for the targeted database.

Entity Framework Work-flow

Note* In this article we will only cover the Code-First approach only.

  1. We start with defining the Conceptual Model - the Domain Classes.
  2. Write queries against the models we defined in above step (LINQ to Entities)
  3. Entity Framework breaks the queries(defined in above step) down into Command Trees
  4. Then the EF provider transforms these Command Trees into appropriate sequel queries for the targeted database
  5. EF determines and executes SQL
  6. EF transforms results into objects of Domain classes that we defined in the very first step.

Here are some more details about EF that you might find interesting:

  • Entity Framework is an Open Source Initiative.
  • Entity Framework is independent of .NET release cycle
  • Entity Framework can be used with a variety of databases (many 3party providers available)
  • Entity Framework can create parametrized queries. Depends on how you have specified your LINQ queries.
  • Entity Framework is able to track in-memory changes made to our conceptual models. Once you call SaveChanges() method EF will execute the appropriate Insert/Update or Delete queries to reflect the in-memory changes that have been made.
  • Entity Framework is flexible and provides for granular control, if need be.
  • Entity Framework provides for better Query Performance via Auto Cached Queries

So, before we begin keep this in mind - " If you do what is easy your life will be hard, if you do what is hard your life will be easy. "

Time to roll...

Code First Driven Approach

Things to remember before we begin are...

  • We do not have any Visual Designer
  • We do not have any automatic Code Generation
  • The Database - May or May NOT Exists. (we will look into this soon enough)
  • Final thing, we "Love Code" and hate the other two approaches - Database First and Model First

So, what comes in Code First approach:

  1. The Domain Classes
    These Domain Classes have nothing to do with Entity Framework. They just represent your Business Domain items.

  2. The Entity Framework
    Then we declare the Context Class. This Context Class manages the interaction between our Domain Classes and the Database. Now, it is worth mentioning that Context Class is not specific to Code First approach, and is an Entity Framework feature and is also employed in Model First and Database First approaches for orchestrating Database interaction.

    The special thing is that - Code First adds and uses DbContext Class as an Model Builder which inspects the Context Class and the Domain Classes that it is managing along with a set of rules that we define via - Code First Data Annotations or Code First Fluent API or using both mentioned to determine how our Domain Classes and their relationships describe the database model and how it should be exactly mapped to the database.

  3. We also get the option to Initialise the database and/or use Code First Migrations Initialisation will help us in seeding the database with some data to begin with. Migrations will help us to update our Database schema if any changes happen to our Domain Classes Model.

So lets start, things we will do in this article are mentioned below

  1. We will create Code First default model and create a database from it
  2. Manage and understand how Domain Model changes reflect/affect on the database
  3. Manage Configurations - Declaratively with Data Annotations and Imperatively with Fluent API
  4. We will end with reversing an existing database for Code First

The Project that we will be Developing

We will be developing database model for a - Discussion Board.

I am given to understand Discussions are essential part to facilitate an evolving progressive society. So, now would be a good time to have one with the 2016 US elections not so far off.

Let us build the back-end to facilitate discussions as the one pointed above.

Our proposed application "Discussion Board" will need the following tables - next to them I have specified the purpose to have those tables.

Table Name Purpose to have the Table
Category The Category that the discussion falls into. Some valid examples are - Technology, Politics, Science, Sports among countless others.
Topic The Topic that the discussion is about. Some valid examples are - Say under category "Politics" Why is "Elizabeth Warren" not contesting in 2016 elections? Note* a Topic can also be linked to more than 1 Category. Example - Will Mr Gates ever buy a Basketball Team? or will he continiue making wise investements that will benefit humanity.? The above topic may very well qualify under two Categories - 1. Technology and 2. Sports.
Comment The Comment that is about a topic. Some valid example are - say under the above mentioned Topic: I have no clue why "Elizabeth Warren" is not running for Presidency. She would be a delight to vote for.
Member The table that will store Member details. Like Member First Name, Last Name, Preferred Name etc
ContactDetail The table that will store Contact Details of the Member. Like Twitter Alias, Facebook Profile id etc. Don't worry we are all for anonymity and if we were developing a full fledged application we would allow for complete anonymity. These details are here just to flesh up our mock database.
Interest The table that will store Interests details of the Member. Like this if a member interests includes Science, Sports etc We will record that information in this table.
  Special Note for you to consider... Category and Topic table will share a Many-to-Many* relationship.

The Project - Quick Look at the Domain Classes

Creating a class library Project which will house the definition of all of our Domain CLasses mentioned above. Note* I have already created a Visual Studio Solution named: "CodeFirst.DiscussionBoard" We will be adding projects to this solution.

Image 1 Screen-shot

Image 2 Screen-shot

The project created

Image 3 Screen-shot

Note* Delete the following class, we do not need it.

Image 4 Screen-shot

Now we will start building the real project. Add the following class files to the project.

We will begin with adding a class name "Category"

  • Step 1

    Image 5 Screen-shot

  • Step 2

    Image 6 Screen-shot

the class added...

Image 7 Screen-shot

Now add the following classes - repeating the above two steps mentioned.

  1. "Topic"
  2. "Comment"
  3. "Member"
  4. "ContactDetail"
  5. "Interest"

The classes have been added...

Image 8 Screen-shot

Now we will add content to the above defined classes. We will add properties to the above classes which will later map to database table columns. So as an example - Category Class will map to an Category Table and any properties in it will map to the columns that the Category Table will have.

I will go ahead and add the required properties to the above classes. There are fairly simple properties and I will add comments in code to explain anything that might come across as a bit twisty.

Screen-Shots after the details(Properties) have been added to the above created classes:

  • Category Class

    Image 9 Screen-shot
     
  • Topic Class

    Image 10 Screen-shot
     
  • Comment Class

    Image 11 Screen-shot
     
  • Member Class

    Image 12 Screen-shot
     
  • ContactDetail Class

    Image 13 Screen-shot
     
  • Interest Class

    Image 14 Screen-shot
     

One thing to note is that our Library Project: "DiscussionBoard.DomainClasses" will have no reference to Entity Framework whatsoever. This will just be plain classes representing our Business Domain.

We will start with adding Enum Type that will be used in Category and Interest Classes. Below is the new Enum and the modified Category and Interest Classes.

Image 15 Screen-shot

Category Class modified property

Image 16 Screen-shot

Interest Class modified property

Image 17 Screen-shot

A final Note - There are Navigation Properties in the above classes - these properties facilitate to manage relationships better in Entity Framework. They also help with something called Lazy Loading (which we will see shortly) virtual keyword* helps us here.

Example of Navigation Property

// Snippet from Comment.cs

// The Topic this Comment is related too
public int TopicId { get; set; }

// Navigation Property to Topic
public virtual Topic Topic { get; set; }

Note* we have TopicId but still we have a virtual property of Type Topic named Topic.

Similar to Comment class other classes also have Navigation Properties. We have this navigation properties for reasons mentioed above.

Now we have our simple domain model ready and so next up.. We will create the DbContext Class.

Creating DbContext Class

So, in the above setion we created our simple POCO classes representing our business domain.

Our Domain classes had no reference to Entity Framework whatsoever.

Of course the next question that follows is how will we engage Entity Framework? We will do this by Introducing a Data Layer that will have reference to Entity Framework. We will also point our Data Layer to the above created business Domain CLasses.

Needless to add - The Data Layer will manage our business domain classes with respect to Entity Framework. This includes - but is not limited to - managing change tracking, fetching data from the database among other things.

Creating a New Project in our Solution:

Image 18 Screen-shot

Note* Delete Class1.cs and add a new class called "DiscussionBoardContext"

Project added -

Image 19 Screen-shot

Now lets add Entity Framework to the Solution and point our newly created project DiscussionBoard.DataLayer to use it.

Steps to add EF to the solution:

Image 20 Screen-shot

Image 21 Screen-shot

Uncheck - the Domain Classes Project. And accept the licence terms & conditions when prompeted.

Image 22 Screen-shot

Now we have the latest stable version of EF (which is version 6 as off writing) in our solution.

The project structure now. We have app.config and package.config files added to our Data Layer project. Also, our Data Layer project now has Entity Framework DLL under its reference.

Image 23 Screen-shot

The app.config SAMPLE file (The one in my Project is diffrent - I have provided that below) It has some default configuration. Note* LocalDbConnectionFactory is part of SQL Server 2012 and is the default developement database that you will use instead of SQL Express and it gets installed with Visual Studio 2012 (and above) editions. If you are running a prior version of VS than it will automatically default to SQL Express. so no worries at all.

Image 24 Screen-shot

However, I am running SQL Server 2014 and for me it defaults to SQL Express. I have not installed LocalDb and so it defaults to SQL Express. My App.config file has the following configuration settings:

Image 24a Screen-shot

The package.config file - Nothing complicated here.

Image 25 Screen-shot

Now it is time to roll in the DbContext.

We will inherit EF's DbContext class in our Data Layer's DiscussionBoardContext class.

Image 26 Screen-shot

Image 27 Screen-shot

DbContext added, now our DiscussionBoardContext class will be able to do all the Entity Framework related tasks because it now inherits from DbContext.

Image 28 Screen-shot

Now we want DiscussionBoardContext to manage our business domain classes. We will achive this by using DbSet Note* I will leave it to you to google what DbSet is? it is fairly straight forward. Here are some pointers regarding DbSet though(this should cover the most important bits):

  • DbSet: Manages Operations (Set Operations) like: Add, Attach, Remove, Find
  • DbSet: is a Collection of a Single Entity Type (usually maps to one Business Domain Class)
  • DbSet: is employed alongside DbContext to query the database
  • DbSet: is a member of System.Data.Entity

An example:

public DbSet<Student> Students { get; set; }

The DbSet of Students will be employed to manage instances, queries and updates to the database of the Student(s) Object.

You will get a better idea of DbSet once we employ it in our Data Layer Project.

Before we introduce DbSets we need to first add reference to our Domain Classes Project in our Data Layer. (Follow Screenshots below.)

Image 29 Screen-shot

Image 30 Screen-shot

Image 31 Screen-shot

Time to add DbSets of our Business Domain Classes. It is a simple process follow the screenshot below.

Image 32 Screen-shot

One interesting detail that has emerged is that I have not created a DbSet for ContactDetail Domain Class. And this is because I know for a fact that I will not be intercating with ContactDetail on a one on one basis. That is to say I will not be querying for ContactDetail explicitly. Since, ContactDetail share a One-To-One or One-To-Zero relationship with Member I would only like to retrieve them when fetching a Member record. EF Code First will support this because it know of this relationship through our Business Domain Model. We will still be able to fetch ContactDetail of a Member even though we do not have a DbSet for it.

Side Note* we have our complete Domain in just one Context Class. It will work for us becuase the application we have here is straight forward and simple. For complex application you might want to look up at something called Domain Driven Design.


Interacting With the DataBase

Entity Framework relies on Meta-Data describing the Conceptual Model Schema(CMS), the Database Structure Schema(DSS) and the Mapping (between CMS and DSS) to interact with the Database.

In regards to Code-First Entity Framework builds Model Meta-Data on the fly at run-time. It infers this data based on the DbSets the Context is managing along with the relationships and properties defined in the Domain Classes themselves (which the DbSets manage).

We can use a Tool (a power tool) perhaps to create a read-only visual model to give us a better understanding of how Entity Framework has interpreted our Domain Model.

This will help us to build the models that we want and will remove the guess work from model meta-data generated by Code-First on the fly. Since we would already have a sneak-peak of how it will translate our doamin model.

Let us look at this Power Tool next.

Installing the proposed Power Tool (Follow the screenshots below):

Image 33 Screen-shot

Image 34 Screen-shot

Now that we have the tool installed let us generate the Database Model from Context Class.

Right click on DiscussionBoardContext.cs and follow the screenshot below:

Image 35 Screen-shot

wops an Error has occured. looking at the bottom of VS... we see the following

Image 36 Screen-shot

Looking at the Output window we see the following error The error is regarding: System.IO.FileNotFoundException

Image 37 Screen-shot

Now, we get the above error because the current Start-Up Project is: DiscussionBoard.DomainClasses and the DiscussionBoard.DomainClasses project does not have an App.config file.

Image 38 Screen-shot

So, let us set DiscussionBoard.DataLayer Project to be the Start-Up Project and DiscussionBoard.DataLayer project has an App.config file (which has the necessary DB Connection string etc)

Image 39 Screen-shot

DiscussionBoard.DataLayer Project has been set as Start-Up Project and has App.config file

Image 40 Screen-shot

Now lets try again to generate the DB Model...

Image 41 Screen-shot

ahh.. more errors.

Image 42 Screen-shot

I must add that this tool also validates our model and is good to have it verify our model befor ewe build our database - well it makes identifying errors/issues easier and in early stages - so it is much cheaper to fix issues as well.

This time the tool is complaining about the following: Error Type is: System.Reflection.TargetInvocationException

Well to cut long story short the validation failed becuase our Domain Class ContactDetail does not have a Primary Key declared.

Needless, to add Entity Framework has a rule that every entity must have an Key and so the validation error was thrown, since the tool failed to find one for ContactDetail. The convention that EF follows while looking for KEY is that every entity must have a property named Option 1:Id or Option 2: property named entityName suffixed by Id like EntityNameId Valid Example for ContactDetail entity would have been the following...

Option 1 example:

// In ContactDetail Class
public class ContactDetail
{
    // Key Property Option 1
    public int Id { get; set; } 
}

OR Option 2 example:

// In ContactDetail Class
public class ContactDetail
{
    // Key Property Option 2 - entityName suffixed by Id
    public int ContactDetailId { get; set; } 
}

Flashback. - ContactDetail Domain Class:

Image 43 Screen-shot

Since, we have not decalred a KEY in ContactDetail using the above specified conventions (demonstrated via Option 1 and Option 2 examples) We get the validation error.

Now Code First gives us to ways to provide configuration information for when EF cannot implicitly infer things properly using conventions. (as in our case with ContactDetail)

We can fix this using 2 approaches:

  1. Data Annotations
  2. Fluent API

for now we will fix this using Data Annotations.

Employing Data Annotations in ContactDetail Class to declare Primary Key.

All we need to do is Flag a property as KEY using the KEY annotation...

Image 44 Screen-shot

the RED Squiggly Lines (under [Key] annotation) indicate all is not well We will need to add the required namespace to our ContactDetail class

Follow the steps below as demonstrated in screen-shots:

Image 45 Screen-shot

Under Framework.. select System.ComponentModel.DataAnnotations

Image 46 Screen-shot

Once done... lets go back to ContactDetail and add the required Namespace

Image 47 Screen-shot

Namespace added and all is good.

Image 48 Screen-shot

Now lets run the tool again...

Image 49 Screen-shot

damn still more errors.

Image 50 Screen-shot

We are getting close though...

Now this time validation failed beacuse of - one confusing convention of Entity Framework.

The complain now is because of this confusing convention: Well to put it simply: when we have a

  • One-To-One relationship
  • One-To-ZeroOrOne relationship

Code First needs to understand which is the Principal End and which is the Dependent End of the relationship. This will help Code First determine which table in the Database will have the Foreign Key pointing to the other table.

So, lets use Data Annotations again to clearly specify this One-to-One or One-to-ZeroOrOne relationship between Member Table and ContactDetail Table.

We can do this by specifying the Foreign Key annotation.

Follow the screenshots below: (Screenshots of ContactDetail Class)

Image 51 Screen-shot

again Foreign Key Annotation lives in System.ComponentModel.DataAnnotations.Schema namespace Lets add the required namespace

Image 52 Screen-shot

ContactDetail Class now

Image 53 Screen-shot

Note* One important thing to note is that just specifying Foreign Key attribute will not do the trick here. We will need to specify Foreign Key to what? and by employing Navigation Property we can do this. Hence, the attribute is pointing to Member Navigation Property (it is not the Property Type but the Property Name as highlighted in the above screen-shot in Yellow).

woha.. finally lets run the Tool again...

Image 49 Screen-shot

and volla we have our (read-only) Model Displayed. Hard work payed off...

Image 54 Screen-shot

Now, that we have a validated model... lets move on to the next step...
 

Database Initialisation

Code-First doesnt really care about the database until upto runtime... but when it gets to that point it does the following two things:

  • Step 1 - Locate the Database (the connection String from App.config is put to use here)
  • Step 2 - Create the Database, if necessary

Here is how this works, the very first time a DbContext class tries to interact with the Database (at application run-time) Code First will perform "DataBase Initialisation "

It starts with looking for a Connection String, once that is figured out (App.Config helps out here) It looks for the Database - by default the database name that Code First looks for will be the fully qualified name of the DbContext Class

In our case this would be: The Namespace followed by the DbContext Class Name - highlighted below

Image 55 Screen-shot

The next step Code First will do is check whether the Database of Datbase Name: "DiscussionBoard.DataLayer.DiscussionBoardContext" exists or not Of course the next logical step that Code First does is - If the Database does not exist than it will create it Needless to add Code First will use the Meta-Data that the Model builder created to determine the Schema of the database. Once the database is in existance Code First will go ahead and do whatever the Context was instructed to do example - Insert a record etc.

Of course, I know you are now curious to see this Default Behaviour in Action.

Well your wait is over - lets roll...



Please Note* In this article we will rely on a Console Application Project for Database Interaction.
I will complie an article on MVC in the future which will use our DiscussionBoard Database
in it. Once, this article is online - it should take me another 45 days or so to get the proposed MVC
article up and running (I only do this in evenings after work-hours, so this takes time. hope you will understand).

To do so, we would need to create a Console Application Project and than reference our Data Layer Project in it...
Follow the steps below...

Image 56 Screen-shot

Image 57 Screen-shot

Image 58 Screen-shot

Now we will reference Entity Framework and DiscussionBoard.DataLayer Project in your newly created Console Application Project.

Referencing DiscussionBoard.DataLayer Project

Image 59 Screen-shot

Image 60 Screen-shot

Reference has been added

Image 61 Screen-shot

Referencing Entity Framework

Image 62 Screen-shot

Image 63 Screen-shot

Press Ok - after selecting Project in - Selected Projects Dialog Box

Image 64 Screen-shot

We have the reference now

Image 65 Screen-shot

We have App.Config (with required Connection String and other information) in DiscussionBoard.ConsoleApplication and we can delete App.Config from DiscussionBoard.DataLayer project since we will be doing all the interaction from our newly created Console Application Project: DiscussionBoard.ConsoleApplication

Image 66 Screen-shot

Image 67 Screen-shot

Select Ok when the SCccARY Dialog Box Promts.

After Deletion of App.Config from DiscussionBoard.DataLayer project

Image 68 Screen-shot

Note* Please also add reference to project DiscussionBoard.DomainClasses in our Console Application.

Now lets add some code to Program.cs class in DiscussionBoard.ConsoleApplication Project. I have added Comments in Code to explain what the code is upto...

Image 69 Screen-shot

One thing to note is at this point in runtime -

C#
// Snippet from Program.cs Class
var members = context.Members.ToList();

Code First relaises that it has to do something it will go and find the Connection String and check whether the database exists or not. So, important thing to note here is that Code First does not jumps to action when DiscussionBoardContext class is initialsied.

Now, needless to add that when we run our Console Application at this point nothing will be returned because, the database does not exist as of yet.

Let run it anyway... Make sure Start-Up Project is set to DiscussionBoard.ConsoleApplication Press F5

All we will get is a Blank Black Screen.

Image 70 Screen-shot

Lets look under the hood and understand what really happened Open up SQL Server Object Explorer

Image 71 Screen-shot

Note* If you do not have SQL Server Object Explorer, than you would need to install SQL Server Data Tools which can be downloaded from this LINK Please select the correct version and install it.

Once SQL Server Object Explorer is located, go under the SQL Express Database

If your SQL Express Database is missing you can add it by doing the following

Image 72 Screen-shot

Select the database and Connect to it

Image 73 Screen-shot

After connecting - locate the Database created by Code First as below

Image 74 Screen-shot

Now, in the next section - I will try to explain the Database that Code First created for us.

Explaining the Database created by Code First

Open up the database - see below We will start with the NAME of the Database - which is: "DiscussionBoard.DataLayer.DiscussionBoardContext" As explained in the above section - The default database name will be the fully qualified name for the Context Class.

Image 75 Screen-shot

Lets look at the tables, there is something interesting there

It is important to mention here that it is the MODEL of our CODE that has dictated the Structure of the Database. Take a closer look at the database SCHEMA

Image 76 Screen-shot

So, our database just looks like the Model that we created in our Data Layer Project (Remember the Model we generated using Power Tools.)

Needless, to add the Classes (in Domain Class Project) are represented here as the Tables and their Properties as Columns.

Relationships were defined using Data Annotaions in Domain Classes Project.

Interesting tables to look at are ContactDetail and TopicsCategory.

Lets look at ContactDetail first

Image 77 Screen-shot

MemberId Column is Primary Key and also a Foreign Key in the Table. This was the result of the Data Anotations that we specified in ContactDetail Class. Have a look at ContactDetail Class for a quick refresher, if you like.

Lets look at TopicsCategory table You might already be wondering that we do NOT have any Class defined by this table name than how does this table came into existance.

Well, we did define a Many-to-Many* relationship between Category and Topic Classes in our Domain Classes Project.

And the way Entity Framework and the Database work that type of relationship out is by having a JOIN Table. in the Database. TopicsCategory is that JOIN Table.

So, in our application whenever we will use the Many-to-Many* relationship specified between Category and Topic our dear all powerful Entity Framework, will translate that into SEQUEL STATEMENTS that will employ this JOIN Table. Making it easier for our database to understand what is it that we are trying to do - example Fetching/Inserting/Updating/Deleting etc.

Image 78 Screen-shot
 

Lets understand CodeFirst Migrations

Now, that we have our Model and Database what will happen if we decide to change it?

That is to say, if we decide to add a new column to Comment Table.

To do so, we would need to add a new column to COMMENT Class in our Domain Class Project(DiscussionBoard.DomainClasses)

Lets add new column named - NumberOfLikes to Comment Class.

Image 79 Screen-shot

Build the Projects and run Console Application again - we will check what will happen - Remember we have changed our MODEL.

Image 80 Screen-shot

WoopSss... adding a new column has broken our project. Self-Explaining Exception - The highlighted bit explains what is the Problem.

We got this exception because the default behaviour of the Database Initialisation does NOT ALLOW for Model changes.

Time to Fix this issue that has crept up becaue we have updated the Model after the Database was created In REAL WORLD this is a very possible scenario - we will have to update our database schema. it is important that this exception be addressed.

DRUM ROLLS - Walks in Code First Migrations. to solve the above Problem.

We need to tell Code First that instead of using Database Initialisation it should use its Migrations feature.

Entity Frameworks Database Migrations API- takes care of managing and keeping in-line the Database Schema as our Domain Model changes/evolves. Migrations - accomplish managing this by keeping track of changes between the model and database (they do so by managing a hash of database schema.)

What we will start with is First: We will let Code First know that we would like to use MigrationsSecond: We will create our initial database using Migrations (So, feel free to delete you database of this project if it already exists. This can be done from SQL Server Management Studio.Also, Commnet out the NumberOfLikes Property in Comment Class in DiscussionBoard.DomainClasses Project.)

So, let us get to work and apprise Code First of our intentions of using Migrations

Open up Package Manager Console

Image 81 Screen-shot

Make sure you have selected Default Project as "DiscussionBoard.DataLayer"

Image 82 Screen-shot

Time to play with some simple commands In Package Manager console type in "enable-migrations" , we can pass on some parameters to this command but we will stick to the defaults

Image 83 Screen-shot

So, this command enable-migrations will first check if the database exists and than it will go and enable migrations. shown in the screen-shot below...

Image 84 Screen-shot

Running enable-migrations command has made some changes to our DiscussionBoard.DataLayer Project We have a New Folder created called: Migrations and this folder has a class created called: Configuration.cs

The Folder:

Image 85 Screen-shot

Configuration Class Default Code This class is specific to Migrations (inheriting from DbMigrationsConfiguration) also, it is setting up this configuration for our context class: DiscussionBoardContext (highlighted below). We will leave the parameter "AutomaticMigrationsEnabled" as false in Configuration.cs and the importance of Seed Method is that it is executed prior to every Migration run. So, if one wants to push some default data into the database every time Migration takes place they will leverage Seed Method. Notice - some sample code has already been provided in Seed Method to add default initial data.

Image 86 Screen-shot

The Code First Database Migrations Process is basically a 3 step process:

  1. Define OR make Changes to a Model (Define (initial Database Creation)/Change (modifying existing database schema) both employ the code model that we have in DiscussionBoard.DomainClasses project)

  2. Creating a Migration File: This is the file that represents the current state of our Model. This file is employed to identify the changes that are to be made to the database, in order to allign it with our Model.

  3. Applying the above created Migration File to the database. No further explanation required here :P

Now, before moving on please make sure you have deleted (if it still exists) your alredy created Database for the Project and Make sure the Property NumberOfLikes is commented out in Comment.cs class.

So, here we go.

Open Package Manager Console and select DiscussionBoard.DataLayer Project

Type in Command: add-migration InitialMigration20151014

Follow the screen-shots below:

Image 87 Screen-shot

Here, in command add-migration - migration is the class that EF creates to describe the changes that will be needed in the database. The parameter that follows add-migration command is just the name of the migration. I have choosen the name InitialMigration20151014. But you can use more descriptive names etc.

First the above command checked that did I had any migrations before of which there were none. So, it will build up the migration files/classes based on this fact. that this is the very initial migration and even the database doesnt exist yet. So, what EF is migrating from is NOTHING, therefore it needs to create everything from scrath..

Have a look at the classes added by the executing the above command to understand better.

The Files:

Image 88 Screen-shot

Have a look at the Class - InitialMigration20151014.cs under Migrations Folder.

Image 89 Screen-shot

Since, this is the very first migration, class InitialMigration20151014.cs has been populated with create table and other relevant methods. Note* This code will be translated to appropriate SQL Code... Yes Migration API is that well built. :)

So, thus far we have completed Step 1 and Step 2 Step 1 was define the Model which we already did in previous sections Step 2 was Creating a Migration File which we did with the Help of command: add-migration InitialMigration20151014

Now, it is time to execute Step 3 - Apply the Migration File.

The command update-database will update our database model to the latest migration, by DEFAULT. You might have noiced the TimeStamp on migration files - that how Entity Frameworkj identifies which migration is the latest.

Now, thet ar emany parameter that can be used with update-database command but I want you to go through these two commands, as I think they are very important in a developers day-to-day chores.

NOTE* Before continuing please move the App.Config file from DiscussionBoard.ConsoleApplication Project to DiscussionBoard.DataLayer Project for the time being. Since we will be excuting Migration command in Package Manager Console for our DiscussionBoard.DataLayer Project.
 

  1. update-database command with the -script Parameter This will generate an SQL Script that can be passed to a DBA so that the model changes could be applied to the database by him/her.

    Usage: In Package Manager Console type - update-database -script

    Image 90 Screen-shot

    A Script File named: SqlQuery_1.sql has been generated. Now, this file can be passed on to the DBA for further proceeds.

    Image 91 Screen-shot

    I will, skip this file as I will be using the second parameter for this project. Running low on resources and I am understaffed so cant afford a DBA for this CP Project :P

    **Please make sure you have re-added App.config file to DiscussionBoard.DataLayer Project for this command to work successfully.**
     
  2. update-database command with the -verbose Parameter This will update the database and will also provide us with a blow-by-blow detail of the update process in the Package Manager Console.

    For us it will create the database as well, as we have deleted our database before starting this migrations article section.

    Usage: In Package Manager Console type - update-database -verbose

    Image 92 Screen-shot

    -verbose in action Part 1

    Image 93 Screen-shot

    -verbose in action Part 2 - Running the Seed Method as we do not have a database.

    Image 94 Screen-shot

    **Please make sure you have re-added App.config file to DiscussionBoard.DataLayer Project for this command to work successfully.**

and now our database has been created this time with the power of Migrations on our side.

Image 95 Screen-shot

Now, we will uncomment/re-add NumberOfLikes Property in Comment.cs Class (DiscussionBoard.DomainClasses Project)

So, we have a MODEL CHANGE this time around. How do we go by updating the Database to our latest Code Data Model... Next steps will discuss that in detail.

Tapping into the power of Migrations to pass on our domain model changes - the addintion of NumberOfLikes Property to database. This will reflect as - a New Column Named NumberOfLikes will be added to the Comment Table.

Before we start as of yet, NumberOfLikes Column does not exist on Comment Table:

Image 96 Screen-shot

NOTE*: Also, worth mentioning is the fact that the table dbo.MigrationHistory in our database is the table that Entity Framework uses to store a hash in and each time we Add a migration Entity Framework works out the difference between the database schema and the code model basd on that stored hash in dbo.MigrationHistory.

Now lets start the Migrations Process -

  1. Add the New Migration.

    Open up Package Manager Console for DiscussionBoard.DataLayer Project and type in the below mentioned command AddedNumberOfLikesPropertyToCommentClass is just a description for the migration.

    Image 97 Screen-shot

    Command Result:

    Image 98 Screen-shot

    Image 99 Screen-shot

    The migration code class - simple: only the definition of the newly added column exists to update the database schema.

    See, the beauty - we can have an already existing database, can have data in that database and yet we can easliy add columns to tables in that database. Pre-existing indexes, triggers etc nothing will get messed up whatsoever. beauty.

    Image 100 Screen-shot
     
  2. Time to Update the database Schema.

    Open up Package Manager Console for DiscussionBoard.DataLayer Project and type in the below mentioned command

    Image 101 Screen-shot

    Command Result:
    Note* the highlighted bit is the Hash store in dbo.MigrationHistory table.

    Image 102 Screen-shot

    and the new column has been added.

    Image 103 Screen-shot
     

In the next section we will see the ways - of how we can interact with our DiscussionBoard DataBase.

Interacting with Database - Inserting records in Discussion Database

Time to interact with our Database.

We will do the interaction using Project: DiscussionBoard.ConsoleApplication

So, follow along, As of now we do not have any Disscussion Data Whatsoever in our Database...

Over the next few sections we will be adding the following methods to our Console Application.

Image 104 Screen-shot
 

  1. Insert Categories Method Implementation

    So, in the code snippet below this is what we are doing:

    DiscussionBoardContext Context in Using Block has all the required DbSets defined. The DbSet gives us access to interact with each of the defined type.

    In this case we will be working with DbSet of type Catergory. As evident in the following code line: context.Categories.Add(definedCategory);

    Further, We would like to Add the Category to the DbSet. Now the Context already knows we want to work with DbSet of Category and the FACT that we have used the ADD method makes it clear to the context that these category items need to be inserted in the Database. Simple. As evident in the following code line: context.Categories.Add(definedCategory);

    Finally, we call the SaveChanges() Method of the Context. This will excute the Insert Statements for us. Note* SaveChanges() Method will execute everything that the Context is Tracking. For us it is only tracking these new Categories objects, so it will fire a Insert Query for each of them. The code line: context.SaveChanges();

    Before, we run the code, I want to introduce you to new Logging feature that has been introduced in EF6. All we are doing is with our Context Instance we have set its Log Property to the Console.WriteLine Function EF will output the log for us in a console window. Now the console window will display all of the activity that EF did to get the job done. It is a good/nice to have feature, especially while developing. the code line: context.Database.Log = Console.WriteLine;

    the code snippet from Program.cs class in Project: DiscussionBoard.ConsoleApplication

    Image 105 Screen-shot

    Note* before we run please make sure you have uncommneted the call to Method InsertCatergories() in Main Mehtod of Program.cs Class and also commented out Method GetMembers() in the said method and class.

    After Running - the Console Project... the result (I Fired a query in Management Studio 2014)

    the Log Output: (you are welcome to look around - Check the Connection EF makes, Transaction EF Begins etc)

    Image 107 Screen-shot

    The Query result:

    Image 106 Screen-shot

    Before we move ahead - Please add the following code in Project: DiscussionBoard.ConsoleApplication Class Program.cs Method Main. We, are Disabling EF Database Initialization. when we are working with Discussion Board Context Database.SetInitializer(new NullDatabaseInitializer<DiscussionBoardContext>());

    Now, EF will only execute commands related to our specified Context.

    Image 108 Screen-shot

    Note* This is an important aspect and in production Database Initialization should be ideally turned off. Now you will notice that EF only fires queries related to our specified context in the Console Window - where the Logs are being reported.

    So, Now if you re-run the above code - you will witness in the Console Window that EF only fired an Insert Command and nothing else unlike previously where there was a barage of interaction. Good for Performnace..

    Note* You might want to look at AddRange Method of the Context Class. It takes IEnumerable and makes life easier when it comes to working with lists. No need for Foreach blocks.

    Before, we proceed further please make below changes to InsertCatergories() Method  We are making these changes, so, that we do not end up saving duplicates into the database. We could have gone for DropCreateDatabase option as our database initialiser scheme but I am leaving that for you to explore as it is fairly simple. Also, I wish to keep this article as straight forward as possible.

    Image 109 Screen-shot

    the _getInitialCategories() Method.. fairly simple

    Image 110 Screen-shot
     
  2. Insert Topics Method Implementation

    Now that we have had a start with implementing InsertCatergories() Method ,
    in this section I will focus on reteriving records and Inserting Topics records.
    So, Quering Categories Table and Inserting Topics in Topics Table corresponding to a Category.

    the InsertTopics() Method :

    Image 111 Screen-shot

    The code in the above table is self explonatory and comments do the job very well to clarify code.

    Let us run the Project and Insert Some Topics.

    Make sure to Uncomment InsertTopics() Method before pressing F5.

    Debugging the execution...

    The method is about to be invoked..

    Image 112 Screen-shot

    2 Categories records have been found.. as expected..

    Image 113 Screen-shot

    Saving the Topic record - after linking/attaching it to the 2 Categories fetched.

    Image 114 Screen-shot

    ohhh... something is not right here... 2 Insert Statements have been fired to Insert Categories.
    but we already have those Categories..


    Image 115 Screen-shot

    Let us look at the database...

    So records 2 and 3 have been re-inserted. Enum 2 stands Sports for and 3 stands for Technology.

    Image 116 Screen-shot

    This is not what we wanted and hence in Method InsertTopics() we linked the Topic to the 2 retrieved Categories.

    Well, we tried to save an Entity Graph here and could not clearly specify our intentions regarding the Graph. EF interpretted that Topic and attached Categories as to be ADDED. When we say context.Topics.Add(topic); this is interpreted by EF as Topic record and everything attached to it should be ADDED.

    Moreover, the context we used to reterive Categories is different to the one we are using to insert Topic. So, the current context has no knowledge that these Categories were actually pulled from the Database (and EF also discards the fact that the Id column on those Categories is greater than ZERO. yes it does so.).

    We need to find a way around this. there are many elegant solutions using Repository Pattern and Unit of Work Pattern by employing an Interface etc but I will leave that to you to figure out.  For now, I will use a simple approch to address this issue.

    Inserting Graphs.

    We can get around this by explicitly managing the Change Tracker.

    The code..now in InsertTopics() Method ..

    Image 117 Screen-shot

    Now, before we can test it - Please follow the Steps below.
    or else you will get exceptions - login failed etc.

    Delete the Database entirely

    Image 118 Screen-shot

    Image 119 Screen-shot

    COMMENT just for this run - the Code below...

    Image 120 Screen-shot

    Time... to build and run the project.

    Select Run without Debugging

    Image 121 Screen-shot

    Press down any key - for ReadKey() when the Console-Window Pops-up.
    Evidentely you will have to do it for around 5 times or so.. for 5 Category records.

    Image 122 Screen-shot

    Database looks Good.

    Image 124 Screen-shot

    Alright so now its Show-Time.

    Uncomment below Highlighted Code.

    Image 123 Screen-shot

    Rebuild and let us debug the code.

    You are welcome to peek into Context etc at this stage.

    Image 125 Screen-shot

    The Console Log looks Good. No records have been inserted into Categories Table.

    Image 126 Screen-shot

    Querying Database Just to Make sure...

    Categories Table:

    Image 127 Screen-shot

    Topics Table:

    Image 128 Screen-shot

    TopicCategories Table (the managed and used by Entity Framework.)

    Image 129 Screen-shot

    and all looks good.
     
  3. Insert Members Method Implementation

    Now, this will be a fairly simple method.

    I will provide you with the code snippet and leave it for you to play with it.

    Also, I have added some checking code for Topics so the insert bit is not triggered if the record already exists.

    The Code...

    Image 130 Screen-shot

    Some Validation Code that I have added... on the side, to check before the inserts are triggered:

    Image 131 Screen-shot

    the Main Method Now looks like this...

    Image 132 Screen-shot

    My Test Run results:

    The Log File looks alright. Each Member Insert Statement is followed by a ContactDetail Insert Statement.

    Image 133 Screen-shot

    Database Queries:

    Image 134 Screen-shot

    Image 135 Screen-shot

    You are welcome to debug and test InsertMembers Method on you own.
    Leave any questions or troubles you are having in the comments.
     
  4. Insert Interests Method Implementation

    Like good guys we will start with The Validation Method.

    Image 136 Screen-shot

    The Main Method looks like this now...

    Image 137 Screen-shot

    and now the the InsertInterests Method itself.

    Image 139 Screen-shot

    My Test Run results:

    The Log File Looks alright. As expected, Insert Statements are fired for Interest Records only.

    Image 138 Screen-shot

    Database Queries:

    Image 140 Screen-shot

    You are welcome to debug and test InsertInterests Method on you own. Leave any questions or troubles you are having in the comments.
     
  5. Insert ContactDetails Method Implementation

    This Method will not be required as we insert ContactDetail records when we insert Member Records. See InsertMembers Method.

    Also, a ContactDetail record cannot exists on its own. It shares a Zero-to-one relationship with Member Table.
     
  6. Insert Comments Method Implementation

    Like good guys we will start with The Validation Method.

    Image 141 Screen-shot

    The Main Method looks like this now...

    Image 142 Screen-shot

    and now the the InsertComments Method itself.

    Image 143 Screen-shot

    My Test Run results:

    The Log File Looks alright. As expected, Insert Statements are fired for Comments Records only.

    Image 144 Screen-shot

    Database Queries:

    Image 145 Screen-shot

    You are welcome to debug and test InsertComments Method on your own. Leave any questions or troubles you are having in the comments

Interacting with Database - Updating and Querying Discussion Database

Updating the database...

We will update the Comment records that we have added... in the previous section.

Image 146 Screen-shot

Lets, update the comments above to something more meaning full.

We will start with looking at some examples of reteriving data from the Database.

Some, examples of READ queries below:

We will be using LINQ Methods to fetch data from the database.

// Code Snippet 

// ToList() is an LINQ Execution Method
// This will return all the Comments in Comment Table
var comments = context.Comments.ToList();

// FirstOrDefault() is an LINQ Execution Method
// This will return only the First Fetched comment from the Comment Table
var comment = context.Comments.FirstOrDefault();

// This will return all the Comments in Comment Table,
// that will MATCH the where condition.
// This query will fetch all the commenst that have been posted by Member with Id 2.
// the '.where' is not an execution method.
// The query is fired when it reached the ToList() LINQ method.
var comments = context.Comments.where(c => c.MemberId == 2).ToList();

// The Find Method
// The Find Method - is used to reterive a record based on the KEY column
// Key is nothing but the Primary Key in the database for that table.
int primaryKeyValue = 4;
// Fetch the record from Comment Table where Id is 4
var comment = context.Comments.Find(primaryKeyValue);

The above queries will query against the database get back the relevant data and will create doamin/entity objects in this case of Comment for all the relevant records that have been fetched.

We will be using these (actually, have used them so far in this project already.) LINQ Methods to fetch Data from database.

Now, getting back to the task at hand. of Updating records - In this case some Comments.

We will RANDOMLY pick a Comment and Update it.

Note* The code is self explonatory and easy to understand.

the Main Method now... looks like this...

Image 147 Screen-shot

the Update Method...

Image 148 Screen-shot

My Test Run results:

The Log File Looks alright. As expected, Update Statement is fired for Comment Record.

Image 149 Screen-shot

Database Queries:

Image 150 Screen-shot

You are welcome to debug and test UpdateRandomComment Method on your own.
Leave any questions or troubles you are having in the comments.

Note* You can Update Data in disconneted state by using the following example.
Explanation is provided in Code Comments.

The UpdateRandomCommentInDisconnectedState() Method -

Image 151 Screen-shot

The Main Method:

Image 152 Screen-shot

My Test Run results:

The Log File Looks alright. As expected, Update Statement is fired for Comment Record.

Image 153 Screen-shot

Database Queries:

Image 154 Screen-shot

You are welcome to debug and test UpdateRandomCommentInDisconnectedState Method on your own.
Leave any questions or troubles you are having in the comments.
 

 

Interacting with Database - Deleting Records in Discussion Database

The DeleteRandomComment() Method -

Image 155 Screen-shot

The Main Method:

Image 156 Screen-shot

My Test Run results:

Debugging DeleteRandomComment method -

Image 157 Screen-shot

The Log File Looks alright. As expected, Delete Statement is fired for Comment Record.

Image 158 Screen-shot

Database Queries:

Image 159 Screen-shot

You are welcome to debug and test DeleteRandomComment Method on your own.
Leave any questions or troubles you are having in the comments.
 

Interacting with Database - Retrieving Graphs of Data Records from Discussion Database

In this section we will look at the following:

We will look at Eager Loading which is implemented using DbSet.Include() Method.

We will look at Explicit Loading which is implemented using Load() Method.

Implementing RetrievingDataGraphs() Method.

Image 160 Screen-shot

the Main Method...

Image 161 Screen-shot

debugging the Method...



Eager Loading in Action - Comments Loaded for reterived Topic Record...

Image 162 Screen-shot

Image 163 Screen-shot

Explicit Loading in Action - Comments Loaded for reterived Topic Record...

No Comments Loaded yet for reterived Topic Record...

Image 164 Screen-shot

Image 165 Screen-shot

Image 166 Screen-shot

With this, we have come to the end of this Article. :)

You have done well. get a chilled pint, you have earned it. :)

Final Thoughts

This is all for now. Hope you enjoyed the journey.

On a side note - I have written a couple of articles regarding WCF web services, please feel free to explore them at your convenience.

  1. Simple Demo - WCF Web Services Article (SOAP Service)
  2. Simple Demo - WCF AJAX Services Article
  3. Simple Demo - WCF RESTful Web Services Article

Its time for me to sign off. Feel free to ask questions, provide feedback and everything in between as I am on the same boat with you.

PS: The Boat is called "Burn and Learn".

Good Luck. and keep learning :)

History

Version 1 submitted on 15th November 2015.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)