Tuesday, December 10, 2013

Configure Domain Classes in Code-First

As you know that you can create entity data model from existing database in database first approach that has all the metadata information in SSDL, CSDL and MSL so that EF can use this model in querying, change tracking, updating functionality etc.. The same way, entity framework code first allows you to use your domain classes to build the model which in-tern will be used by EF in different activity. Code first suggests certain conventions to follow by your domain classes so that EF can understand it and build the model out of it.

However, if your domain classes don’t follow conventions then you also have the ability to configure your domain classes so that EF can understand it and build the model out of it. There are two ways by which you can configure your domain classes:
  1. DataAnnotation
  2. Fluent API

DataAnnotation:

DataAnnotation is simple attribute based configuration which you can apply on your domain classes and its properties. You can find most of the attributes in System.ComponentModel.DataAnnotations namespace. However, DataAnnotation provides only subset of Fluent API configurations. So if you don’t find some attributes in DataAnnotation then you have to use Fluent API to configure it.

Following is an example of DataAnnotation used in Student Class:
     
    [Table("StudentInfo")]
    public class Student
    {
        public Student() { }
        
        [Key]
        public int SID { get; set; }

        [Column("Name", TypeName="ntext")]
        [MaxLength(20)]
        public string StudentName { get; set; }

        [NotMapped]
        public int? Age { get; set; }
        
        
        public int StdId { get; set; }

        [ForeignKey("StdId")]
        public virtual Standard Standard { get; set; }
    }
        
Fluent API:

Fluent API configuration applied as EF building the model from your domain classes. You can inject the configurations by overriding the DbContext class’s OnModelCreating method as following:
    
    public class SchoolDBContext: DbContext 
    {
        public SchoolDBContext(): base("SchoolDBConnectionString") 
        {
        }

        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
        public DbSet<StudentAddress> StudentAddress { get; set; }
        
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //Configure domain classes using Fluent API here

            base.OnModelCreating(modelBuilder);
        }
    }
        
You can use modelBuilder which is an object of DbModelBuilder class to configure domain classes.

Let’s see DataAnnotation and Fluent API in detail in the next chapter.

Inheritance Strategy in Code-First

In the code first approach, database schema will be created based on the design of your domain classes. You may design your domain classes in object-oriented way where you can use inheritance and polymorphism. Object-oriented systems model has “has a” and “is a” relationships where as SQL based relational model has only “has a” relationships. So how would you map object-oriented with relational database?

There are three different approaches to represent an inheritance hierarchy:

  • Table per Hierarchy (TPH): This approach suggests one table for entire class inheritance hierarchy. Table includes discriminator column which distinguish between inheritance classes.

  • Table per Type (TPT): This approach suggests one table for each classes thus each class will have its persistence table.

  • Table per Concrete class (TPC): This approach suggests one table for one concrete class but not for abstract class. So if you inherit abstract class in multiple concrete classes then properties of abstract class will be part of each table of concrete class.
We are not going into detail here. Visit following reference link to understand it in detail:



Seed Database in Code-First

You can insert data into your database tables in database initialization process. This will be important if you want to provide some test data for your application or to provide some default master data for your application.

To seed data into your database, you have to create custom DB initializer as you created in the previous chapter and override Seed method. Following example show how you can provide default data for Standard table while initializing the School database:
     
    public class SchoolDBInitializer : DropCreateDatabaseAlways<SchoolDBContext>
    {
        protected override void Seed(SchoolDBContext context)
        {
            IList<Standard> defaultStandards = new List<Standard>();

            defaultStandards.Add(new Standard() { StandardName = "Standard 1", Description = "First Standard" });
            defaultStandards.Add(new Standard() { StandardName = "Standard 2", Description = "Second Standard" });
            defaultStandards.Add(new Standard() { StandardName = "Standard 3", Description = "Third Standard" });

            foreach (Standard std in defaultStandards)
                context.Standards.Add(std);

            //All standards will
            base.Seed(context);
        }
    }
        

Turn off DB Initializer in Code-First

You can also turn of DB initializer of your application. Suppose for the production environment you don’t want to lose existing data then you can turn off initializer as following:
     
    public class SchoolDBContext: DbContext 
    {
        public SchoolDBContext() : base("SchoolDBConnectionString")
        {            
            //Disable initializer
            Database.SetInitializer<SchoolDBContext>(null);
        }
        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
    }
        
You can also turn off initializer in the configuration file, for example:
    
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>    
        <add key="DatabaseInitializerForType SchoolDataLayer.SchoolDBContext, SchoolDataLayer"
             value="Disabled" />
      </appSettings>
    </configuration>

        

Database Initialization Strategies in Code-First

You already created database after running you code first application first time, but what about second time onwards?? Will it create new database every time you run the application? What about production environment? How to alter database when you change your domain model? To handle these scenarios, you have to use one of the database initialization strategies.

There are four different database Initialization strategies:

  1. CreateDatabaseIfNotExists: This is default initializer. As name suggests, it will create the database if not exists as per the configuration. However, if you change the model class and then run the application with this initializer then it will throw an exception.

  2. DropCreateDatabaseIfModelChanges: This initializer drops existing database and creates new database if your model classes (entity classes) have been changed. So you don’t have to worry about maintaining your database schema when your model classes changes.

  3. DropCreateDatabaseAlways: As name suggests, this initializer drops an existing database every time you run the application irrespective of whether your model classes have changed or not. This will be useful when you want fresh database every time you run the application while developing.

  4. Custom DB Initializer: You can also create your own custom initializer if any of the above doesn’t satisfy your requirement or you want to do some other process when it initialize the database using above initializer.


To use one of the above DB initialization strategies, you have to set the DB Initializer using Database class in Context class as following:
     
    public class SchoolDBContext: DbContext 
    {
        
        public SchoolDBContext(): base("SchoolDBConnectionString") 
        {
            Database.SetInitializer<SchoolDBContext>(new CreateDatabaseIfNotExists<SchoolDBContext>());

            //Database.SetInitializer<SchoolDBContext>(new DropCreateDatabaseIfModelChanges<SchoolDBContext>());
            //Database.SetInitializer<SchoolDBContext>(new DropCreateDatabaseAlways<SchoolDBContext>());
            //Database.SetInitializer<SchoolDBContext>(new SchoolDBInitializer());
        }
        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
    }
        
You can also create your custom DB initializer by inheriting one of the intializer as below:
    
    public class SchoolDBInitializer :  DropCreateDatabaseAlways<SchoolDBContext>
    {
        protected override void Seed(SchoolDBContext context)
        {
            base.Seed(context);
        }
    }
        
As you can see in the above code, we have created new class SchoolDBInitializer which is derived from DropCreateDatabaseAlways initializer.

Set db initializer in the configuration file:

You can also set db initializer in the configuration file. For example, to set default initializer in app.config:
   
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>
        <add key="DatabaseInitializerForType SchoolDataLayer.SchoolDBContext, SchoolDataLayer"         
            value="System.Data.Entity.DropCreateDatabaseAlways`1[[SchoolDataLayer.SchoolDBContext, SchoolDataLayer]], EntityFramework" />
      </appSettings>
    </configuration>
        
You can set custom db initializer as following:
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>    
        <add key="DatabaseInitializerForType SchoolDataLayer.SchoolDBContext, SchoolDataLayer"
             value="SchoolDataLayer.SchoolDBInitializer, SchoolDataLayer" />
      </appSettings>
    </configuration>
        
So this way you can use DB initialization strategy for your application.

Download Sample Project:

Download Entity Framework Sample Project

Database Initialization

Let’s how database initialize in code-first application.

Following figure shows database initialization workflow based on the parameter passed in base constructor of context class which is derived from DbContext:

Entity Framework code-first database initialization
As per above figure, you can pass following parameters in the base constructor:

No Parameter: If you do not pass the parameter then it creates the database in your local SQLEXPRESS with name matches your {Namespace}.{Context class name}. eg. SchoolDataLayer.Context for following context:
     
    public class Context: DbContext 
    {
        public Context(): base()
        {
            
        }
    }
        
Name: If you pass “Name” parameter then it creates database in the local SQLEXPRESS db server using that name. For example: below code will create “SchoolDB-CodeFirst” database
    
    public class Context: DbContext 
    {
        public Context(): base("SchoolDB-CodeFirst") 
        {
                   
        }
    }
        
ConnectionStringName: If you pass connection string name of app.config or web.config then it will create the database as per connection string. For example, below code will create "SchoolDB-ByConnectionString" database:
   
    public class Context: DbContext 
    {
        public SchoolDBContext() : base("SchoolDBConnectionString") 
        {
        }
    }
        
App.config:
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <connectionStrings>
        <add name="SchoolDBConnectionString" 
        connectionString="Data Source=.;Initial Catalog=SchoolDB-ByConnectionString;Integrated Security=true" 
        providerName="System.Data.SqlClient"/>
      </connectionStrings>
    </configuration>
        
Above Context class sends connection string name as a parameter. So it will create new "SchoolDB-ByConnectionString" database or use existing “SchoolDB-ByConnectionString” database at local SQL Server (because we have mentioned '.' not SQLEXPRESS). Make sure that you include providerName = "System.Data.SqlClient" in the connection string.

Simple Code First Example

Let’s create first simple code first example.

Create the Class Library project in Visual Studio 2010. Write two simple Student and Standard entity classes as below (You can use Entity Framework 4.1/4.3/5.0 for this example.):

Student Class:
    
    public class Student
    {
        public Student()
        { 
        
        }
        public int StudentID { get; set; }
        public string StudentName { get; set; }
    }
        
Standard Class:
    
    public class Standard
    {
        public Standard()
        { 
        
        }
        public int StandardId { get; set; }
        public string StandardName { get; set; }
        public string Description { get; set; }
    }
        
Now, create context class which is derived from DBContext class with two DbSet properties, one for Student and one for Standard.
   
    namespace SchoolDataLayer
    {
        
        public class Context: DbContext 
            {
                public Context(): base()
                {
            
                }
                public DbSet<Student> Students { get; set; }
                public DbSet<Standard> Standards { get; set; }
            }
    }
        
Now, create console project to test these classes as below:
     
    using (var ctx = new Context())
    {
        Student stud = new Student() { StudentName = "New Student" };
        ctx.Students.Add(stud);
        ctx.SaveChanges();                
    }
        
Now, if you run the application then you will surprise to see that application run successfully.

It has successfully stored Student information into the database. But where is database and what are the tables and its columns??

This is the beauty of Code First APIs of Entity Framework. It creates the database based on parameter passed in the base constructor of your context class. We have not passed any parameters so it will create “SchoolDataLayer.Context” database in local SQLEXPRESS. We will see database initialization workflow in the next chapter.

Code-first API will also create two tables in the database, Students and Standards table based on Student and Standard class. Code First APIs creates PrimaryKey in the table if class has either “Id” or ClassName + “Id” property. For example, Student class has “StudentId” property so it will create StudentId as PK column. It will also create other columns with the same name and datatype as property names and datatype as below.
Entity Framework code-first example
So this way without creating database first, you can start writing application that will eventually create the database from your domain classes.

Download sample project:

Download Entity Framework Code-First Sample Project