简体   繁体   English

实体框架CTP 4 - 代码优先自定义数据库初始化程序

[英]Entity Framework CTP 4 - Code First Custom Database Initializer

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 supplied User ID and Password. 我想实现一个自定义数据库初始化策略,以便我可以使用提供的用户ID和密码生成数据库模式并将其应用于EXISTING EMPTY SQL数据库。

Unfortunately the built-in strategies don't provide what I'm looking for: 不幸的是,内置策略没有提供我正在寻找的东西:

// The default strategy creates the DB only if it doesn't exist - but it does 
// exist so this does nothing
Database.SetInitializer(new CreateDatabaseOnlyIfNotExists<DataContext>());

// Drops and re-creates the database but then this breaks my security mapping and 
// only works if using a “Trusted" connection
Database.SetInitializer(new RecreateDatabaseIfModelChanges<DataContext>());

// Strategy for always recreating the DB every time the app is run. – no good for 
// what I want
Database.SetInitializer(new AlwaysRecreateDatabase<DataContext>());

I have worked out the following but this does not create the ModelHash so I'm unable to use "context.Database.ModelMatchesDatabase()" to validate that the database schema has been created and prevent multiple initializations: 我已经解决了以下问题,但这不会创建ModelHash,因此我无法使用“context.Database.ModelMatchesDatabase()”来验证是否已创建数据库模式并阻止多次初始化:

public class Initializer : IDatabaseInitializer<DataContext>  
{ 
    Public void InitializeDatabase(DataContext context)  
    {       
         // this generates the SQL script from my POCO Classes
         var sql = context.ObjectContext.CreateDatabaseScript();

         // As expected - when run the second time it bombs out here with "there is already an
         // object named xxxxx in the database"
         context.ObjectContext.ExecuteStoreCommand(sql); 

         this.seed(context)
         context.SaveChanges();
    }
}  

Questions: 问题:

Does anyone know how I can get/create the model hash? 有谁知道如何获取/创建模型哈希? (which is an EdmMetadata Entity) (这是一个EdmMetadata实体)

-Or- -要么-

Is there a better way of doing this in general using the Code First CTP? 使用Code First CTP一般有更好的方法吗?

I ran into the same problem. 我遇到了同样的问题。 I didn't really solve it, but I managed to get a little nasty workaround running, so i can deploy my solution to AppHarbor ;) 我没有真正解决它,但我设法运行了一些讨厌的解决方法,所以我可以将我的解决方案部署到AppHarbor;)

Its a IDatabaseInitializer implementation, that doesn't delete the db, but just nukes all the constraints and tables, and then uses the ObjectContext.CreateDatabaseScript() method to generate the sql, and then I execute it as a storecommand. 它是一个IDatabaseInitializer实现,它不删除数据库,只是核对所有约束和表,然后使用ObjectContext.CreateDatabaseScript()方法生成sql,然后我将它作为storecommand执行。 A lot like the above implementation in the question. 很像问题中的上述实现。

But i also added functionality to create a hash from the model and save it in db, and when it runs again it checks if the current model-hash matches the one i db. 但我还添加了从模型创建哈希并将其保存在db中的功能,当它再次运行时,它检查当前模型哈希是否与i db匹配。 Just like the real code-first implementation. 就像真正的代码优先实现一样。

I couldn't make it work with the build in context.Database.CompatibleWithModel(true) - but this should work just as well, and seeing as its a temporary workaround it should be fine. 我无法使用上下文中的构建工作.Database.CompatibleWithModel(true) - 但这应该也可以正常工作,并将其视为临时解决方法应该没问题。

using System;
using System.Data.Entity;
using System.Data.Entity.Database;
using System.Data.Entity.Design;
using System.Data.Entity.Infrastructure;
using System.Data.Metadata.Edm;
using System.Data.Objects;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using System.Linq;

namespace Devtalk
{
    public class DontDropDbJustCreateTablesIfModelChanged<T> : IDatabaseInitializer<T> where T : DbContext
    {
        private EdmMetadata _edmMetaData;

        public void InitializeDatabase(T context)
        {
            ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
            string modelHash = GetModelHash(objectContext);

            if (CompatibleWithModel(modelHash, context, objectContext)) return;

            DeleteExistingTables(objectContext);
            CreateTables(objectContext);

            SaveModelHashToDatabase(context, modelHash, objectContext);
        }

        private void SaveModelHashToDatabase(T context, string modelHash, ObjectContext objectContext)
        {
            if (_edmMetaData != null) objectContext.Detach(_edmMetaData);

            _edmMetaData = new EdmMetadata();
            context.Set<EdmMetadata>().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(Dropallconstraintsscript);
            objectContext.ExecuteStoreCommand(Deletealltablesscript);
        }

        private string GetModelHash(ObjectContext context)
        {
            var csdlXmlString = GetCsdlXmlString(context).ToString();
            return ComputeSha256Hash(csdlXmlString);
        }

        private bool CompatibleWithModel(string modelHash, DbContext context, ObjectContext objectContext)
        {
            var isEdmMetaDataInStore = objectContext.ExecuteStoreQuery<int>(LookupEdmMetaDataTable).FirstOrDefault();
            if (isEdmMetaDataInStore == 1)
            {            
                _edmMetaData = context.Set<EdmMetadata>().FirstOrDefault();
                if (_edmMetaData != null)
                {
                    return modelHash == _edmMetaData.ModelHash;
                }
            }
            return false;
        }

        private string GetCsdlXmlString(ObjectContext context)
        {
            if (context != null)
            {
                var entityContainerList = context.MetadataWorkspace.GetItems<EntityContainer>(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 Dropallconstraintsscript =
            @"select  
                'ALTER TABLE ' + so.table_name + ' DROP CONSTRAINT ' + so.constraint_name  
                from INFORMATION_SCHEMA.TABLE_CONSTRAINTS so";

        private const string Deletealltablesscript =
            @"declare @cmd varchar(4000)
                declare cmds cursor for 
                Select
                    'drop table [' + Table_Name + ']'
                From
                    INFORMATION_SCHEMA.TABLES

                open cmds
                while 1=1
                begin
                    fetch cmds into @cmd
                    if @@fetch_status != 0 break
                    print @cmd
                    exec(@cmd)
                end
                close cmds
                deallocate cmds";

        private const string LookupEdmMetaDataTable =
            @"Select COUNT(*) 
              FROM INFORMATION_SCHEMA.TABLES T 
              Where T.TABLE_NAME = 'EdmMetaData'";
    }
}

This is the easiest way to get EF Code First running on AppHarbor ! 这是在AppHarbor上运行EF Code First的最简单方法!

Using the EdmMetadata.TryGetModelHash(context) function to check when the model doesn't match the database and showing an error with the new code that needs to be used after you run alteration scripts. 使用EdmMetadata.TryGetModelHash(context)函数检查模型何时与数据库不匹配,并在运行更改脚本后显示需要使用的新代码的错误。

PopulateOnly : Only creates objects when the database is empty PopulateOnly:仅在数据库为空时创建对象

I thought I'd post my own version of the Initializer which I'm currently using on appharbor to populate an existing database . 我以为我会发布我自己的初始化程序版本,我目前正在appharbor上使用填充现有数据库 It will also try to do a create if the database doesn't exists and throws if a change is detected (sorry no automatic updating yet). 如果数据库不存在,它也会尝试进行创建,如果检测到更改则抛出它 (抱歉没有自动更新)。 I hope someone finds it useful. 我希望有人发现它有用。

    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Data.Objects;
    using System.Transactions;

    namespace Deskspace.EntityFramework
    {

        /// <summary> A Database Initializer for appharbor </summary>
        /// <typeparam name="T">Code first context</typeparam>
        public class PopulateOnly<T> : IDatabaseInitializer<T> where T : DbContext
        {
            private EdmMetadata metadata;

            private enum Status
            {
                Compatable,
                Invalid,
                Missing
            }

            /// <summary> Initializer that supports creating or populating a missing or empty database </summary>
            /// <param name="context"> Context to create for </param>
            public void InitializeDatabase(T context)
            {
                // Get metadata hash
                string hash = EdmMetadata.TryGetModelHash(context);

                bool exists;
                using (new TransactionScope( TransactionScopeOption.Suppress )) {
                    exists = context.Database.Exists();
                }

                if (exists) {

                    ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;

                    var dbHash = GetHashFromDatabase( objectContext );

                    Status compatability = 
                            string.IsNullOrEmpty( dbHash )? 
                        Status.Missing : 
                            (dbHash != hash)? 
                        Status.Invalid :
                        Status.Compatable;

                    if (compatability == Status.Missing) {

                        // Drop all database objects
                        ClearDatabase( objectContext );

                        // Recreate database objects
                        CreateTables( objectContext );

                        // Save the new hash
                        SaveHash( objectContext,  hash );

                    } else if (compatability == Status.Invalid) {

                        throw new Exception( 
                            "EdmMetadata does not match, manually update the database, expected: " + 
                            Environment.NewLine + 
                            "<[(" + hash + ")}>"
                        );
                    }
                } else {
                    context.Database.Create();
                    context.SaveChanges();
                }
            }

            private void ClearDatabase(ObjectContext objectContext)
            {
                objectContext.ExecuteStoreCommand( DropAllObjects );
            }

            private void CreateTables(ObjectContext objectContext)
            {
                string dataBaseCreateScript = objectContext.CreateDatabaseScript();
                objectContext.ExecuteStoreCommand( dataBaseCreateScript );
            }

            private void SaveHash(ObjectContext objectContext, string hash)
            {
                objectContext.ExecuteStoreCommand( string.Format(UpdateEdmMetaDataTable, hash.Replace( "'", "''" )) );
            }

            private string GetHashFromDatabase(ObjectContext objectContext)
            {
                foreach (var item in objectContext.ExecuteStoreQuery<string>( GetEdmMetaDataTable )) {
                    return item;
                }

                return string.Empty;
            }

            private const string UpdateEdmMetaDataTable = @"
    Delete From EdmMetadata;
    Insert Into EdmMetadata (ModelHash) Values ('{0}');";

            private const string GetEdmMetaDataTable = @"
    If Exists (Select * From INFORMATION_SCHEMA.TABLES tables where tables.TABLE_NAME = 'EdmMetaData')
        Select Top 1 ModelHash From EdmMetadata;
    Else
        Select '';";

            private const string DropAllObjects = @"
    declare @n char(1)
    set @n = char(10)

    declare @stmt nvarchar(max)

    -- procedures
    select @stmt = isnull( @stmt + @n, '' ) +
        'drop procedure [' + name + ']'
    from sys.procedures

    -- check constraints
    select @stmt = isnull( @stmt + @n, '' ) +
        'alter table [' + object_name( parent_object_id ) + '] drop constraint [' + name + ']'
    from sys.check_constraints

    -- functions
    select @stmt = isnull( @stmt + @n, '' ) +
        'drop function [' + name + ']'
    from sys.objects
    where type in ( 'FN', 'IF', 'TF' )

    -- views
    select @stmt = isnull( @stmt + @n, '' ) +
        'drop view [' + name + ']'
    from sys.views

    -- foreign keys
    select @stmt = isnull( @stmt + @n, '' ) +
        'alter table [' + object_name( parent_object_id ) + '] drop constraint [' + name + ']'
    from sys.foreign_keys

    -- tables
    select @stmt = isnull( @stmt + @n, '' ) +
        'drop table [' + name + ']'
    from sys.tables

    -- user defined types
    select @stmt = isnull( @stmt + @n, '' ) +
        'drop type [' + name + ']'
    from sys.types
    where is_user_defined = 1

    exec sp_executesql @stmt";

        }
    }

Just to contribute to @Luhmann's solution, here's mine but slightly changed to drop the FK and PK properly. 只是为@ Luhmann的解决方案做出贡献,这是我的,但稍微改变了以适当地降低FK和PK。

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<T> : IDatabaseInitializer<T> 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<EdmMetadata>().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<int>(LookupEdmMetaDataTable).FirstOrDefault();
            if (isEdmMetaDataInStore == 1)
            {
                edmMetaData = context.Set<EdmMetadata>().FirstOrDefault();
                if (edmMetaData != null)
                {
                    return modelHash == edmMetaData.ModelHash;
                }
            }
            return false;
        }

        private string GetCsdlXmlString(ObjectContext context)
        {
            if (context != null)
            {
                var entityContainerList = context.MetadataWorkspace.GetItems<EntityContainer>(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'";
    }
}

I took a slightly different approach to this problem. 我对这个问题略有不同。 This seems like as good a place as any to share the results. 这似乎是分享结果的好地方。

I want to only create tables that don't already exist in the database. 我只想创建数据库中尚不存在的表。 This has the benefit of being able to roll out new tables without erasing the rest of the database. 这样做的好处是能够在不擦除数据库其余部分的情况下推出新表。

This also helps if you have multiple data contexts in an inheritance chain. 如果在继承链中有多个数据上下文,这也会有所帮助。 For example, if you split your application into different assemblies. 例如,如果将应用程序拆分为不同的程序集。 You might have a data context in a "core" module, and then inherit it in a different assembly for add-on modules. 您可能在“核心”模块中具有数据上下文,然后在附加模块的不同程序集中继承它。 This configuration works fine, but the built-in Drop/Create initializers don't like it because the model hash is changing all the time. 此配置工作正常,但内置的Drop / Create初始值设定项不喜欢它,因为模型哈希值一直在变化。 By checking table existance, initialization takes slightly longer, but then you have none of these issues. 通过检查表存在,初始化需要稍长,但是你没有这些问题。

Anyway, here's the code: 无论如何,这是代码:

/// <summary>
/// Database Initializer to create tables only if they don't already exist.
/// It will never drop the database.  Does not check the model for compatibility.
/// </summary>
/// <typeparam name="TContext">The data context</typeparam>
public class CreateTablesOnlyIfTheyDontExist<TContext> : IDatabaseInitializer<TContext>
  where TContext : DataContext
{
  public void InitializeDatabase(TContext context)
  {
    using (new TransactionScope(TransactionScopeOption.Suppress))
    {
      // If the database doesn't exist at all then just create it like normal.
      if (!context.Database.Exists())
      {
        context.Database.Create();
        return;
      }

      // get the object context
      var objectContext = ((IObjectContextAdapter)context).ObjectContext;

      // get the database creation script
      var script = objectContext.CreateDatabaseScript();


      if (context.Database.Connection is SqlConnection)
      {
        // for SQL Server, we'll just alter the script

        // add existance checks to the table creation statements
        script = Regex.Replace(script,
          @"create table \[(\w+)\]\.\[(\w+)\]",
          "if not exists (select * from INFORMATION_SCHEMA.TABLES " +
          "where TABLE_SCHEMA='$1' and TABLE_NAME = '$2')\n$&");

        // add existance checks to the table constraint creation statements
        script = Regex.Replace(script,
          @"alter table \[(\w+)\]\.\[(\w+)\] add constraint \[(\w+)\]",
          "if not exists (select * from INFORMATION_SCHEMA.TABLE_CONSTRAINTS " +
          "where TABLE_SCHEMA='$1' and TABLE_NAME = '$2' " +
          "and CONSTRAINT_NAME = '$3')\n$&");

        // run the modified script
        objectContext.ExecuteStoreCommand(script);
      }
      else if (context.Database.Connection is SqlCeConnection)
      {
        // SQL CE doesn't let you use inline existance checks,
        // so we have to parse each statement out and check separately.

        var statements = script.Split(new[] { ";\r\n" },
                        StringSplitOptions.RemoveEmptyEntries);
        foreach (var statement in statements)
        {
          var quoteSplitStrings = statement.Split('"');
          if (statement.StartsWith("CREATE TABLE"))
          {
            // Create a table if it does not exist.
            var tableName = quoteSplitStrings[1];
            const string sql = 
              "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES " +
              "WHERE TABLE_NAME='{0}'"
            var checkScript = string.Format(sql, tableName);
            if (objectContext.ExecuteStoreQuery<int>(checkScript).First() == 0)
              objectContext.ExecuteStoreCommand(statement);
          }
          else if (statement.Contains("ADD CONSTRAINT"))
          {
            // Add a table constraint if it does not exist.
            var tableName = quoteSplitStrings[1];
            var constraintName = quoteSplitStrings[3];
            const string sql = 
              "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS " +
              "WHERE TABLE_NAME='{0}' AND CONSTRAINT_NAME='{1}'";
            var checkScript = string.Format(sql, tableName, constraintName);
            if (objectContext.ExecuteStoreQuery<int>(checkScript).First() == 0)
              objectContext.ExecuteStoreCommand(statement);
          }
          else
          {
            // Not sure what else it could be. Just run it.
            objectContext.ExecuteStoreCommand(statement);
          }
        }
      }
      else
      {
        throw new InvalidOperationException(
          "This initializer is only compatible with SQL Server or SQL Compact Edition"
          );
      }
    }
  }
}

I too was looking for a good solution since godaddy does not allow drop/creation of database and thus no tables created. 我也在寻找一个好的解决方案,因为godaddy不允许删除/创建数据库,因此没有创建表。 Since the newer version of Entity Framework has obsoleted EDMData, I modified Alex's code to see if a DropMeToRecreateDatabase table exists or not, if it doesnt exist, it deletes all tables and recreates new tables. 由于较新版本的Entity Framework已废弃EDMData,我修改了Alex的代码以查看DropMeToRecreateDatabase表是否存在,如果它不存在,则删除所有表并重新创建新表。

using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
using System.Linq;

namespace LadyTreble.DatabaseInitializer
{

    public class DontDropExistingDbCreateTablesIfTableDropped<T> : IDatabaseInitializer<T> where T : DbContext
    {
        public bool TryInitializeDatabase(T context)
        {
            var objectContext = ((IObjectContextAdapter)context).ObjectContext;
            if (objectContext.ExecuteStoreQuery<int>(GetTableCount).FirstOrDefault() == 0)
            {
                this.DeleteExistingTables(objectContext);
                this.CreateTables(objectContext);
            }
            return true;
        }

        public void InitializeDatabase(T context)
        {
            this.TryInitializeDatabase(context);
        }

        private void CreateTables(ObjectContext objectContext)
        {
            string dataBaseCreateScript = objectContext.CreateDatabaseScript();
            objectContext.ExecuteStoreCommand(dataBaseCreateScript);
        }

        private void DeleteExistingTables(ObjectContext objectContext)
        {

            objectContext.ExecuteStoreCommand(DeleteAllTablesScript);
        }

        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

             CREATE TABLE DropMeToRecreateDatabase(id int IDENTITY(1,1) NOT NULL)";

        private const string GetTableCount =
            @"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES T WHERE T.TABLE_NAME = 'DropMeToRecreateDatabase'";
    }

}

The Entity Designer Database Generation Power Pack will do this. 实体设计器数据库生成Power Pack将执行此操作。 Not sure if it works with Code First yet, but worth a shot. 不确定它是否适用于Code First,但值得一试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM