Entity Framework CTP 4 - Code First Custom Database Initializer

后端 未结 6 655
傲寒
傲寒 2020-11-28 23:53

I would like to implement a custom database initialization strategy so that I can generate the database schema and apply it to an EXISTING EMPTY SQL database using a supplie

6条回答
  •  情话喂你
    2020-11-29 00:38

    Just to contribute to @Luhmann's solution, here's mine but slightly changed to drop the FK and PK properly.

    using System.Data.Entity;
    using System.Data.Entity.Design;
    using System.Data.Entity.Infrastructure;
    using System.Data.Metadata.Edm;
    using System.Data.Objects;
    using System.Globalization;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Text;
    using System.Xml;
    
    namespace SISQuote.Server.Persistence
    {
        public class DontDropExistingDbCreateTablesIfModelChanged : IDatabaseInitializer where T : DbContext
        {
            private EdmMetadata edmMetaData;
    
            public bool TryInitializeDatabase(T context)
            {
                ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
                string modelHash = GetModelHash(objectContext);
    
                if (CompatibleWithModel(modelHash, context, objectContext))
                    return false;
    
                DeleteExistingTables(objectContext);
                CreateTables(objectContext);
                SaveModelHashToDatabase(context, modelHash, objectContext);
    
                return true;
            }
    
            public void InitializeDatabase(T context)
            {
                TryInitializeDatabase(context);
            }
    
            private void SaveModelHashToDatabase(T context, string modelHash, ObjectContext objectContext)
            {
                if (edmMetaData != null) 
                    objectContext.Detach(edmMetaData);
    
                edmMetaData = new EdmMetadata();
                context.Set().Add(edmMetaData);
    
                edmMetaData.ModelHash = modelHash;
                context.SaveChanges();
            }
    
            private void CreateTables(ObjectContext objectContext)
            {
                string dataBaseCreateScript = objectContext.CreateDatabaseScript();
                objectContext.ExecuteStoreCommand(dataBaseCreateScript);
            }
    
            private void DeleteExistingTables(ObjectContext objectContext)
            {
                objectContext.ExecuteStoreCommand(DeleteAllTablesScript);
            }
    
            private string GetModelHash(ObjectContext context)
            {
                var csdlXmlString = GetCsdlXmlString(context).ToString();
                return ComputeSha256Hash(csdlXmlString);
            }
    
            public bool CompatibleWithModel(DbContext context)
            {
                ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
                return CompatibleWithModel(GetModelHash(objectContext), context, objectContext);
            }
    
            private bool CompatibleWithModel(string modelHash, DbContext context, ObjectContext objectContext)
            {
                var isEdmMetaDataInStore = objectContext.ExecuteStoreQuery(LookupEdmMetaDataTable).FirstOrDefault();
                if (isEdmMetaDataInStore == 1)
                {
                    edmMetaData = context.Set().FirstOrDefault();
                    if (edmMetaData != null)
                    {
                        return modelHash == edmMetaData.ModelHash;
                    }
                }
                return false;
            }
    
            private string GetCsdlXmlString(ObjectContext context)
            {
                if (context != null)
                {
                    var entityContainerList = context.MetadataWorkspace.GetItems(DataSpace.SSpace);
                    if (entityContainerList != null)
                    {
                        EntityContainer entityContainer = entityContainerList.FirstOrDefault();
                        var generator = new EntityModelSchemaGenerator(entityContainer);
                        var stringBuilder = new StringBuilder();
                        var xmlWRiter = XmlWriter.Create(stringBuilder);
                        generator.GenerateMetadata();
                        generator.WriteModelSchema(xmlWRiter);
                        xmlWRiter.Flush();
                        return stringBuilder.ToString();
                    }
                }
                return string.Empty;
            }
    
            private static string ComputeSha256Hash(string input)
            {
                byte[] buffer = new SHA256Managed().ComputeHash(Encoding.ASCII.GetBytes(input));
                var builder = new StringBuilder(buffer.Length * 2);
                foreach (byte num in buffer)
                {
                    builder.Append(num.ToString("X2", CultureInfo.InvariantCulture));
                }
                return builder.ToString();
            }
    
            private const string DeleteAllTablesScript =
                @"declare @cmd varchar(4000)
    
                  DECLARE cmds0 CURSOR FOR 
                  SELECT 'ALTER TABLE ' + TABLE_NAME + ' DROP CONSTRAINT ' + CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'FOREIGN KEY'
    
                  DECLARE cmds1 CURSOR FOR 
                  SELECT 'ALTER TABLE ' + TABLE_NAME + ' DROP CONSTRAINT ' + CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
    
                  DECLARE cmds2 CURSOR FOR 
                  SELECT 'TRUNCATE TABLE ' + TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
    
                  DECLARE cmds3 CURSOR FOR 
                  SELECT 'DROP TABLE [' + TABLE_NAME + ']' FROM INFORMATION_SCHEMA.TABLES
    
                  open cmds0
                  while 1=1
                  begin
                      fetch cmds0 into @cmd
                      if @@fetch_status != 0 break
                      print @cmd
                      exec(@cmd)
                  end
                  close cmds0
                  deallocate cmds0
    
                  open cmds1
                  while 1=1
                  begin
                      fetch cmds1 into @cmd
                      if @@fetch_status != 0 break
                      print @cmd
                      exec(@cmd)
                  end
                  close cmds1
                  deallocate cmds1
    
                  open cmds2
                  while 1=1
                  begin
                      fetch cmds2 into @cmd
                      if @@fetch_status != 0 break
                      print @cmd
                      exec(@cmd)
                  end
                  close cmds2
                  deallocate cmds2
    
                  open cmds3
                  while 1=1
                  begin
                      fetch cmds3 into @cmd
                      if @@fetch_status != 0 break
                      print @cmd
                      exec(@cmd)
                  end
                  close cmds3
                  deallocate cmds3";
    
            private const string LookupEdmMetaDataTable =
                @"Select COUNT(*) 
                  FROM INFORMATION_SCHEMA.TABLES T 
                  Where T.TABLE_NAME = 'EdmMetaData'";
        }
    }
    

提交回复
热议问题