📜 ⬆️ ⬇️

My bike Entity FrameWork, Auto Migration, With Save Data

I love bikes.

In the process of writing software using EF, the structure often changes, which creates problems. Up to version 4.3 - re-creation of the database with data loss and the need to fill the test.
Since version 4.3. Migration appeared. Migration cleared a headache with the removal of all data. But the manual description of the update mechanism of the database - I'm tired after 2 migrations. Automatic migration is what you need. Minus one, with a strong change in structure (field type, field from 1 table to another) - data is lost.
As a result, a bicycle appeared.
When changing the structure of the database.
1. Determines the version from the last update;
2. Disconnects the database from the SQL server;
3. Copy the database files (next to the original) FILEBD -> FILEBD_VERSION;
4. Attaches the original under the old name;
5. Attaches a copy under the name OLD.VERSION;
6. Applies automatic migration;
7. Write down the version;

Main advantages for me:
1. Updating the structure without unnecessary questions;
2. Preservation of accumulated data that can be manually dragged over (we are not afraid of T-SQL :))
')
public class RenameCreateDatabaseIfModelChanged<TContext> : IDatabaseInitializer<TContext> where TContext : System.Data.Entity.DbContext { public void InitializeDatabase(TContext context) { int version = 1; DbCommand cmd; if (context.Database.Exists()) { bool throwIfNoMetadata = true; if (context.Database.CompatibleWithModel(throwIfNoMetadata)) { return; } DbDataReader dr; context.Database.Connection.Open(); //GET VERSION cmd = context.Database.Connection.CreateCommand(); cmd.CommandText = "SELECT TOP 1 * FROM sysobjects WHERE xtype='U' AND name = '__ase.version'"; dr = cmd.ExecuteReader(); if (dr.Read()) { //VERSION EXISTS dr.Close(); cmd.CommandText = "SELECT TOP 1 Vesion FROM [__ase.version] ORDER BY CreatedOn DESC"; dr = cmd.ExecuteReader(); if (dr.Read()) version = (int)dr["Vesion"]; dr.Close(); version++; } else { //First dr.Close(); cmd.CommandText = "CREATE TABLE [__ase.version] ([Vesion] [int] NOT NULL, [CreatedOn] [datetime] NOT NULL)"; cmd.ExecuteNonQuery(); //WriteVersion(context, version); } //Get list files List<string> files = new List<string>(); cmd.CommandText = "EXEC SP_HELPFILE"; dr = cmd.ExecuteReader(); while (dr.Read()) { files.Add(dr["filename"].ToString()); } dr.Close(); //Disconnect all connections cmd.CommandText = String.Format("ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", context.Database.Connection.Database); cmd.ExecuteNonQuery(); cmd.CommandText = String.Format("ALTER DATABASE [{0}] SET MULTI_USER WITH ROLLBACK IMMEDIATE", context.Database.Connection.Database); cmd.ExecuteNonQuery(); string dbName = context.Database.Connection.Database; //Deattach database cmd.CommandText = String.Format("USE MASTER; EXEC SP_DETACH_DB [{0}]", dbName); cmd.ExecuteNonQuery(); //Copy database string sql_file_old = String.Format("EXEC SP_ATTACH_DB [{0}], ", dbName); string sql_file_new = String.Format("EXEC SP_ATTACH_DB [{0}.{1}], ", dbName, version); foreach (string file in files) { File.Copy(file, file + "_" + version); sql_file_old += "'" + file + "', "; sql_file_new += "'" + file + "_" + version + "', "; } //Attach database cmd.CommandText = sql_file_old.Substring(0, sql_file_old.Length - 2); cmd.ExecuteNonQuery(); //Attach copy database cmd.CommandText = sql_file_new.Substring(0, sql_file_new.Length - 2); cmd.ExecuteNonQuery(); context.Database.Connection.Close(); } //Migrate with data loss var configuration = new DbMigrationsConfiguration<TContext>(); configuration.AutomaticMigrationDataLossAllowed = true; configuration.AutomaticMigrationsEnabled = true; var migrator = new DbMigrator(configuration); migrator.Update(); //Update version context.Database.Connection.Open(); cmd = context.Database.Connection.CreateCommand(); DbParameter param = cmd.CreateParameter(); param.ParameterName = "@v1"; param.Value = version; cmd.Parameters.Add(param); param = cmd.CreateParameter(); param.ParameterName = "@v2"; param.Value = DateTime.Now; cmd.Parameters.Add(param); cmd.CommandText = "INSERT INTO [__ase.version] ([Vesion], [CreatedOn]) VALUES (@v1, @v2)"; cmd.ExecuteNonQuery(); context.Database.Connection.Close(); } protected virtual void Seed(TContext context) { } } public class InitData : RenameCreateDatabaseIfModelChanged<AppEntities> { protected override void Seed(AppEntities context) { base.Seed(context); } } System.Data.Entity.Database.SetInitializer<AppEntities>(new InitData()); 

Source: https://habr.com/ru/post/146137/


All Articles