Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Manage Entity Framework Code First in Real Time Projects

0.00/5 (No votes)
29 Jul 2014 1  
How to manage Entity Framework Code First in Real Time Projects

Introduction

Entity framework is really a great framework to work with. And the code first approach is becoming popular day by day. But if we don’t use entity framework code first in a proper way, it may turn into a devastating scenario. So in this article, I will try to illustrate, what type of problems I have faced working with entity framework and how we can use this framework in a sure way.

Background

Before starting, I am assuming that we have little knowledge about entity framework code first. At least, we know how to create tables, relations and using seed data in entity framework.

If we don’t know, it wouldn’t be that hard to start with:

Or just Google for some time, it would be just fine.

So, what entity framework code first needs?

  1. Models: to turn them into tables …
  2. Configurations for models: to create relations between tables, and formatting table columns structures …
  3. Context: to represent the database, connections, calling model configurations, database initializations, database load configurations …
  4. Initializers: to initialize database context, using seeds …
  5. Migrations: if model changes how to deal with old data or structures ...

What Are the Problems that You Have Been Taking About?

The problems start when we are misusing sections like:

  1. Initialization of database context
  2. Working with migrations

Let’s explain those sections.

1. Initialization of Database Context

To initialize Database context, we can use IDatabaseInitializers classes like:

CreateDatabaseIfNotExists – creates database first, if there is no database available for the application, specified by the context and connection string (good for live projects)

But my host provider is not letting me to do such a thing. It asks me to create database manually, then use. What should I do now?

Updated requirement forces you to add a new field to a table. So you did and provided the updated context. Now if we run the application, exception would be thrown pointing to the current context and existing database doesn’t match with one another. What should I do now?

DropCreateDatabaseIfModelChanges – drops the old database if it doesn’t match with the updated context, and creates new database as the context is pointing (good for development)

Updated requirement forces you to add a new field to a table. So you did and provided the updated context. Now if we run the application, then the old database would be dropped. All data would be lost. What should I do now?

DropCreateDatabaseAlways - drops the old database and creates a new one every time, whenever the context is initialized. (Good for testing, if database is small in size.)

We will not be able to store enough data to work with. No way should we use it, if the application is one real-time action. What should I do now?

So some say, why not use CreateDatabaseIfNotExists for live projects, DropCreateDatabaseIfModelChanges during development, and SQL Script to create database for the first time. When we go live, replace DropCreateDatabaseIfModelChanges with CreateDatabaseIfNotExists, and the problem is solved. What about if one day, we provide the update, but forget to do so?

2. Working With Migrations

Migration is really a good way to work with entity frame work code first. It enables the database to hold information like, how many migrations have been made and when. Plus in migration files, we can find out what changes were made even we do go back and forth between migrations. In the next post, we will talk about it.

But the problem is, it is a little bit tricky to configure. If you have less time to do research, migration may force you to omit the option to use entity framework code first. Because some times, day by day applications expand so much, which enforce us to make changes in the database data and tables relations, etc.

And people don’t like to take risks for big projects. They want to handle things as they used to do with SQL Scripts.

What Is the Solution?

Here is the clue, Entity Framework can also be used to map context to existing database. So what are we going to do?

  1. Use a builder context for database, which uses DropCreateDatabaseIfModelChanges. The context’s access in limited to a particular project only, not to other projects of the solution. Or can be inherited by other projects codes (using internal/ protected internal as access modifier). This will be used to rebuild the database.
  2. Use a mapper context for database, which is only mapped to database entities. This will be mainly used by application to affect tables.
  3. Inheriting common contents from Base context, for field table and configuration files

Mapper Context

Mapper context is simple as such, which inherits base Context class.

We will use this context for any CRUD operations.

/*Context is only mapped to bd objects*/
public class UmsContext : Context
{
    public UmsContext() : base("DbUms")    //connection string name to base          
    {
        /*Configuration for the context*/
        Configuration.ProxyCreationEnabled = false;
        Configuration.LazyLoadingEnabled = false;
    }
}

Builder Context

Builder context which also inherits from base Context class and its initializer class is like:

We will use this context class only to recreate the database:

/*Context drops the old database and creates new one*/
internal class UmsBuildContext : Context
{
    static UmsBuildContext()
    {
        //check connection string
        string connectionString = ConfigurationManager.ConnectionStrings["DbUms"].ConnectionString;
        Database.SetInitializer(new UmsBuildContextInitializer());
    }

    public UmsBuildContext()
        : base("DbUms") //connection string name to base
    {
    }
}

Initializer may also have seeds like this:

internal class UmsBuildContextInitializer
    : DropCreateDatabaseIfModelChanges<UmsBuildContext>
{
    protected override void Seed(UmsBuildContext context)
    {
        /*department seeds*/
        List<Department> departments = new List<Department>()
        {
            new Department(){Name = "Math"},
            new Department(){Name = "Physics"},
            new Department(){Name = "Chemistry"},              
        };
        context.Departments.AddRange(departments);
        context.SaveChanges();

        /*students seeds*/
        List<Student> students = new List<Student>()
        {
            new Student(){ Name = "Nitol", DepartmentId = 1},
            new Student(){ Name = "Tasnim", DepartmentId = 2},
            new Student(){ Name = "Ripon", DepartmentId = 3}
        };
        context.Students.AddRange(students);
        context.SaveChanges();
    }
}

As we said, we want to set limit to the builder context. That’s why we are using internal as access modifier for UmsBuildContext. But it is also required to use this context for test projects to recreate the database for tests/ intentionally. So to access some of its functionality, we are using this class inside a public class like:

public class DbBuilder
{
    public void Build()
    {
        var departments = new UmsBuildContext().Departments.ToList();
    }
}

Base Context

The main base context is mainly holding all the table configurations and database entity references, and the above contexts are inheriting it.

public class Context : DbContext
{
    /*all tbls*/
    public DbSet<Department> Departments { get; set; }
    public DbSet<Student> Students { get; set; }

    /*connection string provided by the sub class*/
    protected Context(string connectionString)
        : base(nameOrConnectionString: connectionString)
    {
    }

    /*get tbl by tbl type*/
    public DbSet<TSource> Table<TSource>() where TSource : class
    {
        return Set<TSource>();
    }

    /*all tbls configurations*/
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new DepartmentConfiguration());
        modelBuilder.Configurations.Add(new StudentConfiguration());
    }
}

Using the Code

So if any change is made to the database structure, and we want to rebuild the hold database, we only have to call:

/*Rebuild the db*/
//use only when we want to rebuild the database with seed data during production.
//avoid any use when the product is already been delivered to client.(best use in test code)
new DbBuilder().Build();

Now, let’s test the mapper context:

/*see the datas*/
var db = new UmsContext();
var departments = db.Departments.ToList();
var departments2 = db.Table<Department>().ToList();

/*add new student with new department*/
var student = new Student()
{
    Name = "Rintu",
    Department = new Department() {Name = "CSE"}
};
db.Students.Add(student);
db.SaveChanges();

Here, a new student and its department row would be created in the database which means the mapper is working fine.

Change Structure of the Database

To do so, we just have to:

  1. Modify the model class
  2. Rebuild the database at local machine
  3. Compare recreated database with the old one, to find the required alter/ update SQL-quires to update old database to the current version, and use such queries to the old database.
  4. Replace old DLL with the newly created one

Limitations

  1. Yes, there could be some errors which I haven't faced yet, or could make some ethical disturbance. So if you find any, just let me know.
  2. I am not discouraging anyone to use migrations. If you have time, just do some RNDs
  3. The rebuild system may seem a little bit creepy, but I am working to make it more logical.
public class DbBuilder
{
    public void Build()
    {
        var departments = new UmsBuildContext().Departments.ToList();
    }
}

or just take a look at this, http://stackoverflow.com/questions/4911329/ef-codefirst-ctp5-manually-drop-and-create-db

Find Visual Studio 2010 solution of framework 4 projects at the attachment. If you run the project, it would create a "UMS" database with 3 tables, at the local machine. You can change it using app.config.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here