How to handle Entity Framework Model without losing previous data in production deploy?

Viewed 212

Originally I used EF 6 code first approach to create tables in LocalDB (Service-based Database). The code is:

namespace WindowsFormsApp2
{
   public class MyDBContext : DbContext
   {
    public MyDBContext() : base("name=strCon")
    {
        AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ""));
        Database.SetInitializer<MyDBContext>(new DropCreateDatabaseIfModelChanges<MyDBContext>());
        //Database.SetInitializer<MyDBContext>(null);
        //Database.SetInitializer<MyDBContext>(new CreateDatabaseIfNotExists<MyDBContext>());
    }
    public DbSet<Assets> Assets { get; set; }
}
}

Connection string in App.config for LocalDB

 <connectionStrings>
 <add name="strCon" connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\AppDB.mdf;Integrated Security=True;Connect Timeout=30" providerName="System.Data.SqlClient" />
 </connectionStrings>

My goal is to deploy (publish) on the client machine with the latest model changes without losing the previous data in tables. Database migrations should perform programmatically. But database Initializer DropCreateDatabaseIfModelChanges is DELETE, RECREATING on the database. Is it possible that EF6 still does not handle such a basic model change automatically without delete, recreate?

2 Answers

You are initializing your context using DropCreateDatabaseIfModelChanges. As the name suggests, if the model changes it drops the database completely and creates it again. If this is not the desired action you should be using something like CreateDatabaseIfNotExists to maintain the existing data.

Here is the Solution:

Automated Migration in Entity Framework should perform model change automatically without losing the data in both development or production or LocalDB.

namespace WindowsFormsApp3
{
public class MyDBContext:DbContext
{
    public MyDBContext() : base("name=strCon") {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDBContext, WindowsFormsApp3.Migrations.Configuration>());
    }
    public DbSet<Employee> Employee { get; set; }
 }
}

You should run Enable-Migrations in Package Manage Console to generate Configuration.cs file.

Here is the code in my Configuration.cs file.

namespace WindowsFormsApp3.Migrations
{
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;

internal sealed class Configuration : DbMigrationsConfiguration<WindowsFormsApp3.MyDBContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
    }

    protected override void Seed(WindowsFormsApp3.MyDBContext context)
    {
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
        //  to avoid creating duplicate seed data.
    }
 }
}

For Service-based database You need to set .mdf file property Copy to output Directory to Copy if newer from Copy always.

Connection string in App.config file:

<connectionStrings>
    <add name="strCon" connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\WinForms3.mdf;Integrated Security=True;Connect Timeout=30" providerName="System.Data.SqlClient" />
</connectionStrings>

Now, you can add or modify entities in model classes. You don't need to run any command in Package Manager Console.

Important

Note that you have to set AutomaticMigrationDataLossAllowed to true in the Configuration class constructor, along with AutomaticMigrationsEnabled = true; these two options should handle the data loss in corresponding columns exceptions kind or scenario.

Related