Sunday, July 6, 2014

Various strategies to initialize Database in Entity Framework

This is the second article of this series, In our first article we have seen, how to start with code first approach in Entity Framework? You can read it here.


 Ok, so we got the idea of code first and other approaches and learned when and how it will help in various development scenarios. In discussion we have seen that it’s need to write code at first in code first approach and then database will get generate. The approach is very clear and straight forward. Now, let’s think the scenario when we have written code and generated database and after then we decided to change something in database. It may be adding a new property (column ,in terms of database relational schema) or deletion of old one Or we might think to change relationship between tables. Now, database is already created previously, so shall we modify the existing database and create new one? . Entity Framework has given four options to handle the situation. They are.
  1.          Create database If not exists
  2.          Create database always
  3.          Create database when model change
  4.          customize

In this article we will discuss one by one and know how to implement in Entity Frame code first approach.

Create database if not exists
This is the attempt for first time run, generally at first the database did not create and we can set the setting in context class , so when the database is not present the setting is useful. Have a look on below code.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace CodeFirst
{
    public class Person
    {
        [Key]
        public int PersonId { get; set; }
        [Required]
        [MaxLength(10)]
        public string Name { get; set; }
        public string surname { get; set; }
    }

    public class TestContext : DbContext
    {
        public TestContext()
            : base("DBConnectionString")
        {
            //Create database always, even If exhists
            Database.SetInitializer<TestContext>(new  CreateDatabaseIfNotExists<TestContext>());
        }
        public DbSet<Person> Students { get; set; }
    }
}
The implementation is very simple, we have created Person model and TestContext class to initialize the database using code first approach. Please note that we are passing the connection string through constructor , the connection string should configure in web.config file in same application. Here is mine.

<connectionStrings>
    <add name="DBConnectionString"
    connectionString="Data Source=SERVERNAME;Initial Catalog=PersonDB;Integrated Security=true"
    providerName="System.Data.SqlClient"/>
</connectionStrings>


Just configure your connection string according to your environment and once you run the application, you will see it has created database as below.


Create database always
In this approach, database will create always whether it already exists or not? So, in each run of the code it will drop the database if exist and will create one brand new database.  So, when brand new database will create obviously the old data will get lost if exist anything. So, definitely be sure your database seeding code is available always in this approach in development environment. Here is the configuration for create database always approach. The model (Person) is same in this example too.

public class TestContext : DbContext
    {
        public TestContext()
            : base("DBConnectionString")
        {
            //Create database always, even If exhists
            Database.SetInitializer<TestContext>(new  DropCreateDatabaseAlways<TestContext>());
        }
        public DbSet<Person> Students { get; set; }
    }

If Model Changes
This is another fantastic approach to generate database, in my concern. The database will get generate when model in code will not match with database model. Here is the code to set the approach.

public class TestContext : DbContext
    {
        public TestContext()
            : base("DBConnectionString")
        {
            //Create database always, even If exhists
            Database.SetInitializer<TestContext>(new DropCreateDatabaseIfModelChanges<TestContext>());
        }
        public DbSet<Person> Students { get; set; }
    }


Custom Initialize
This is the last and most important one, The approach is very much flexible and the full control is in developer’s hand. Developer can decide when database will get generate and new database will create according to new code. Have a look in below implementation.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace CodeFirst
{
    public class Person
    {
        [Key]
        public int PersonId { get; set; }
        [Required]
        [MaxLength(10)]
        public string Name { get; set; }
        public string surname { get; set; }
    }

    public class PersonDBInitializer : DropCreateDatabaseAlways<TestContext>
    {
        protected override void Seed(TestContext context)
        {
            base.Seed(context);
        }
    }

    public class TestContext : DbContext
    {
        public TestContext()
            : base("DBConnectionString")
        {
            //Create database always, even If exhists
            Database.SetInitializer<TestContext>(new PersonDBInitializer());
        }
        public DbSet<Person> Students { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (var ctx = new TestContext())
            {
                new PersonDBInitializer().InitializeDatabase(ctx);
            }
        }
    }
}

In this approach , we have introduce another class called DBInitializer class and calling SetInitialise method by creating object of PersonDBInitializer class.

Seeding data into Database
This is the bonus topic I wanted to introduce the mechanism to set some default data in brand new database. Sometimes it’s very much useful when we want some default data along with newly created database. Have a look on below code.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace CodeFirst
{
    public class Person
    {
        [Key]
        public int PersonId { get; set; }
        [Required]
        [MaxLength(10)]
        public string Name { get; set; }
        public string surname { get; set; }
    }

    public class PersonDBInitializer : DropCreateDatabaseAlways<TestContext>
    {
        List<Person> persons = new List<Person>();
        public PersonDBInitializer()
        {
            persons.Add(new Person { Name = "sourav", surname = "kayal" });
            persons.Add(new Person { Name = "foo", surname = "bar" });
        }
        protected override void Seed(TestContext context)
        {
            foreach (Person p in persons)
            {
                context.Students.Add(p);
            }
            context.SaveChanges();
            base.Seed(context);
        }
    }

    public class TestContext : DbContext
    {
        public TestContext()
            : base("DBConnectionString")
        {
            //Create database always, even If exhists
            Database.SetInitializer<TestContext>(new PersonDBInitializer());
        }
        public DbSet<Person> Students { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (var ctx = new TestContext())
            {
                new PersonDBInitializer().InitializeDatabase(ctx);
            }
        }
    }
}
This code will set the default data in Person table.

Border line:
In this article we have seen various approaches to initialize database in code first approach , hope it will help you. In next article I am interested to discuss inheritance in code first approach in Entity Framework.


No comments:

Post a Comment