Working with Enums

by Sachin Singh


Posted on Friday, 08 January 2021

Tags: Enums in Database-First approach Entity Framework Enums with EF

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.

Course Table
Course Table

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

Create new project
Create a new project

Step 3.Install Entity Framework.

With the new project the first step is to Install EF. To do that , we use package manager console.

Package Manager Console
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

successfully installed EF
EF installed successfully message

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.

Add New Item
Add New Item
Ado.Net Entity Data Model1
Ado.Net Entity Data Model

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.

Entity Data Model Wizard
Entity Data Model Wizard

  • 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.
Entity Data Model Wizard
Entity Data Model Wizard

  • Change the connection name to TutorialDbContext and click on Next.
Database objects and settings
Database objects and settings

  • 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.

TutorialModel.edmx diagram
TutorialModel.edmx diagram

Unfolding Edmx

Unfolding edmx
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.

edmx overview
Edmx overview
context.tt
expand context.tt
edmx overview
expand model.tt

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.

DbContext
DbContext

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.

Course Class
Course Entity generated by EF

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.

Open with
Open with option
open with xml editor
open with XML 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 .

EDMX as XML
open EDMX as XML

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?

Runtime Section
Runtime section

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

Storage Model
Storage Model

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.

Conceptual Model
Conceptual Model

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.

Mappings
Mapping Section

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.

Model Browser
Model Browser
    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.
table mapping
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.

Enum Type
Enum Type
Add New Enum type
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.

Add Enum window
create enum window

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.

open Entity property
Entity property
Change type
Change type to Enum (TutorialModel.Level)

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.

Enum Type
Enum Type
Add New Enum type
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.

 Specify Existing Enum
Specify Existing Enum

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.

open Entity property
Entity property
Change type
Change type to Enum (TutorialModel.CourseLevel)

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();
        }
    }