In C#, an enum (or enumeration type) is used to assign constant names to a group of numeric values. It makes constant values more readable . To understand Enum, have a look to the course Table Shown below.
Here course level 1,2,3 indicates the course difficulty where 1 means the course is for beginners , 2 means, the course is for Intermediates and 3 means , it is for professionals or it is an advance level course.
Suppose we have successfully imported this table into our Entity Data Model and Now we have an Entity called as Course and DbSet of Course called as Courses , so to add more courses to it , we will write code as shown below.
OurDbContext db=new OurDbContext();
var course= new Course();
course.Name= "SQL";
course.Level=2;
db.Courses.Add(course);
db.SaveChanges();
If in future , any developer reads your code then it will be very tough for them to find out what does course level=2 means , so in programming to make our code more readable we give each constant a specific readable name. In c# this is achieved by creating an Enum as shown below.
enum Level
{
Beginner = 1,
Intermediate = 2,
Advance = 6,
}
Now , in our code we can use their Names instead of numbers as shown below.
OurDbContext db=new OurDbContext();
var course= new Course();
course.Name= "SQL";
course.Level=(int)Level.Advance; // Notice here
db.Courses.Add(course);
db.SaveChanges();
Notice , now our code is more readable and robust , But it would be even much better if the level property of Course Entity will directly be an Enum type, in that case we would not need any type casting. Let's understand this with an example.
Public class Course
{
public int Id {get;set;}
public string Name {get;set;}
public Level Level {get;set;} // Level is an Enum type here
OurDbContext db=new OurDbContext();
var course= new Course();
course.Name= "SQL";
course.Level=Level.Advance; // Notice here we don't need type casting
db.Courses.Add(course);
db.SaveChanges();
So, we want the property "Level" as an Enum type in our Entity but in database it is Int , so by default Entity Framework will map it to an Int32 type . In this article we will learn to import Enum into our Entity Data Model, so that we can use Enum as normal data type.
Step 1. Create a database and a table.
Open SSMS and using visual designer create a database , name it as Tutorial and create a table called as Course. If you are not a fan of visual designer and prefer SQL script to generate Database and tables, then copy and paste below code as a new query and run the script.
Create database Tutorial
go
use Tutorial
go
CREATE TABLE [dbo].[Course] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] VARCHAR (50) NULL,
[Level] Int Null,
CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED ([Id] ASC)
);
Step 2.Go to visual studio and create a new project , Name it as DatabaseFirstDemo
The primary focus here is to learn database-first work flow , so for now , i am going to stick to a console app because we don't want to get distracted by the complications of web or desktop app , so to keep things simple and to focus on EF , create a console application.
• Open visual studio.
• Go to Files ---->New---->Project
• Under New Project window select console application.
• Give the project a name (DatabaseFirstDemo)
• Click Ok
Step 3.Install Entity Framework.
With the new project the first step is to Install EF. To do that , we use package manager console.
• Go to Tools.
• Select Nuget Package Manger and Then go to Package Manager Console, for intalling EF.
• Install Entity Framework using the install-package command.
Install-Package EntityFramework -Version 6.2.0
Step 4. Add Ado.Net Entity Data Model.
• Right Click the project.
• Add ----> Add New Item.
• Under Add new Item window select Data tab and under that select Ado.Net Entity Data Model and click Add.
This is going to be our conceptual Model that represents the mapping between our database tables and domain classes. I have given it a meaningful name as TutorialModel.
• Under the Entity Data Model wizard, select EF Designer From database , cause we already have a database and click next.
• In the next window select or specify the connection to your database.
1. Specify Server Name
2. Choose Database.
3. Test the connection and
4. Click Ok.
• Change the connection name to TutorialDbContext and click on Next.
• In the next window select your table and give the model namespace a meaningful name as TutorialModel and click finish as shown above.
Notice : At this point EF looks at our database and displays the tables, views , stored procedure and Functions , currently we only had a table so we just ticked the table and left the rest as is.
At this point , you will get a security warning like "Running this template can harm your computer" , don't worry about it and just click next. It gives us the warning because visual studio tries to run a template to generate the code.
Unfolding Edmx
EF generates domain models by running some templates , these templates are present under an EDMX file , the extension of templates are .tt. Let's uncover these templates . As you Notice in the above figure , we have two templates .
1. TutorialModel.Context.tt and
2. TutorialModel.tt
Here the tt" stands for template , the first template is responsible for generating DbContext and DBSet while the second template is responsible for generating our domain Entities. This is the reason when you expand the first template that is your context.tt you will find your DbContext class, similarly on expanding Model.tt you will find all your domain Entities.
DbContext Class
At this point, if we expand our context class, we see the actual generated code. This is a plain C# code that EF generates for us. This class derives from the DbContext, so we call it our context class. Remember DbContext is an abstraction over the database. It provides a simple API to load the data from a database or save data to the database.
It has properties of type DbSet. A DbSet represents a Table in our Database. As in our database we had one table named Course, so, EF generated a Dbset namely DbSet of Course.
Domain Classes
On expanding the other template that is model.tt we can see our domain Entities. Each domain Entities has properties based on our table columns.
Notice the Level property is of type short , but we want this to be an Enum type , It is a Short type because in our database it is Int , If you have gone through my previous article then would know that EF generates Entity based on Conceptual Model. The EDMX designer that you see is actually a visual representation of XML , Let's check out the real XML which is responsible to generate our Entities in the designer.
Go to solution explorer ,Right click on the Edmx file and open with XML text Editor.
Note : please close the designer before opening the EDMX with XML editor , because you can't open the different representation of same thing in two places at the same time. The XML content is shown in the below figure .
As you can see , it has two main sections
1. EF Runtime content and
2. EF designer content
The designer section includes the data about the visual representation of the EDMX , like if we zoom in the diagram or move entities around , anything we do visually in the designer will be represented here.
The runtime section includes everything about our Entity Data Model , so it is where we are interested in, let's expand this and check what does it contain?
On expanding the Runtime section , we find that it has 3 subsections
1. Storage Models (SSDL)
2. Conceptual Models (CSDL)
3. Mappings (C-S)
Let's take a deeper look at each of these sections
Under storage model, there is data about our database , tables and columns , In short storage model knows everything about our database. Notice the data type of columns are actual SQL server data Type like varchar , int etc and not C# data type like string or int32. So , storage model is a complete replica of our database.
Under conceptual model , there is everything about our Entities , Like Name of the entity , their properties and type of the properties , notice here the data type of properties is actual C# data type and not SQL Server data type , so , we can say, conceptual model represents our Entities completely.
Under Mappings section , the relation between storage model and conceptual model is defined , for example the Name column of Course in storage model maps to the Name property of Course Entity.
The above three section is the core of any ORM , they define how to map a object oriented Model to a Relational Model.
Edit the storage Model , the Conceptual Model or Mappings
whatever we see in the EDMX designer is only our Entities. We don't see the conceptual model , storage model or Mappings between the two , they all are hidden , but it is possible to visually analyze them and modify them as per our requirement, if we need.
• To Edit the Storage Model objects or Conceptual Model objects we use Model Browser.
To open the model browser, Right-click on an empty area in the EDMX designer and Select the Model Browser.
As you can see in below figure the model browser has two section.
1. TutorialModel : it displays the conceptual model in a tree structure.
2. TutorialModel.store : it displays the storage model in a tree structure.
Here we can customize them in case if we need any customization.
• To Edit the mappings we use Table Mapping. To open table mappings , select the Entity for whom you want to see the mappings and select table mappings.
here you can see the Course's Name column in the database maps to Course's Name property of Course Entity. If we want we can alter this mapping if it make sense.
Map Level property to Enum Type
Now we Know , how does Entity Framework work behind the scene and how can we alter things if we need , and clearly , in our case we are not okay with the Level property Data Type , we want it to be an Enum type , we also know that EF generates Entity based on the information it has in its conceptual Model , we also know that to Edit Conceptual Model we use Model Browser , so without any delay let's create an Enum
To create an Enum open model browser and under conceptual Model section , you will find a node named as Enum Type. Right click on it and select add new Enum Type.
It will open a new window , where you can easily create an Enum , just specify the Name and Members of it as shown below , and click ok.
Now , save your EDMX to take bring the changes to the conceptual Model. Remember whenever we make change via Model browser we need to save our EDMX , as soon as we save the EDMX the Entity Framework saves all the changes. Now as our Conceptual Model contains an Enum we can map our Course's level property to it. To do so , open EDMX designer and select the course Entity and Right click on the level column then go to property and change the type of Level from int16 to TutorialModel.Level ,which is our Enum in conceptual Model as shown in below diagram.
To save the changes , save your EDMX , Now we can write cleaner code as shown below.
namespace DatabaseFirstDemo
{
class Program
{
static void Main(string[] args)
{
TutorialDbContext db = new TutorialDbContext();
Course course = new Course();
course.Name = "SQL Server";
course.Level = Level.Advance;
db.Courses.Add(course);
db.SaveChanges();
Console.ReadLine();
}
}
}
How to map property type to an Existing Enum
It is also possible to map the property type to an existing Enum in the project. suppose we have already an Enum defined in our project , then it is not required to unnecessarily creating Enum inside conceptual Model instead we can directly bring it into our conceptual Model using the model browser.
Step 1. Define an Enum into the project.
namespace DatabaseFirstDemo
{
enum CourseLevel
{
Beginner=1,
Intermediate=2,
Advance=3
}
class Program
{
static void Main(string[] args)
{
Console.ReadLine();
}
}
}
Step 2. To bring the existing Enum into the conceptual Model, open model browser and under conceptual Model section , you will find a node named as Enum Type. Right click on it and select add new Enum Type.
It will open a new window , In this window specify the Enum Name as defined in your project and check the check the Reference external Type checkbox and specify the fully qualified name of your Enum that is your NamespaceName.EnumName ,then Save the EDMX to save the changes.
Now as our Conceptual Model contains this Enum we can map our Course's level property to it. To do so , open EDMX designer and select the course Entity and Right click on the level column then go to property and change the type of Level from int16 to TutorialModel.CourseLevel ,which is our Enum in conceptual Model as shown in below diagram.
Notice , at this moment we have two enums into our conceptual Model , in which CourseLevel is the existing one with which we want to map the level property. To save the changes , save your EDMX , Now we can write cleaner code as shown below.
class Program
{
static void Main(string[] args)
{
TutorialDbContext db = new TutorialDbContext();
Course course = new Course();
course.Name = "SQL Server";
course.Level = CourseLevel.Beginner;
db.Courses.Add(course);
db.SaveChanges();
Console.ReadLine();
}
}