SQL Code First DB - 创建表,而不是删除/创建

时间:2011-09-12 23:12:22

标签: entity-framework-4.1 ef-code-first azure-sql-database

我正在尝试在Azure试验下实现MVC 3部署,但似乎已经让EF4.1数据库自行创建了。

运行时,它会成功连接,但会出错:

Invalid object name 'dbo.TableName'.

我相信这是因为数据库存在,但其中没有表格。我已经能够在本地重现它 - 如果删除我的SQL Express数据库,数据库重建工作正常,但如果我删除所有表并离开数据库则不行。

我已经阅读了可以添加到Global.asax的方法:

protected void Application_Start()
{
    // Use any of:
    System.Data.Entity.Database.SetInitializer<MyDatabaseContext>(new DropCreateDatabaseIfModelChanges<MyDatabaseContext>());
    System.Data.Entity.Database.SetInitializer<MyDatabaseContext>(new CreateDatabaseIfNotExists<MyDatabaseContext>());
    System.Data.Entity.Database.SetInitializer<MyDatabaseContext>(new DropCreateDatabaseAlways<MyDatabaseContext>());
}

......似乎没有用。有些人给出了关于不在EdmMetadata表中获取模型哈希的错误。

如何让EF4.1 / Code First在现有数据库中创建数据库结构? (而在Azure ......)。或者我是否必须从SQL Management Studio编写数据库脚本,并针对目标数据库运行它?

3 个答案:

答案 0 :(得分:2)

查看David.Cline(开发)博客,了解“在模型更改时删除并创建表”:

http://www.davidcline.info/2012/05/technologies-c-v4.html

此链接可能会有所帮助:

http://blogs.microsoft.co.il/blogs/gilf/archive/2011/05/30/creating-a-code-first-database-initializer-strategy.aspx

谢谢, Khachatur

答案 1 :(得分:1)

您需要创建一个不同的数据库初始化程序,它只是清理数据库而不是重新创建。

这是

using System.Collections.ObjectModel;
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 Infrastructure
{  
public partial class RecreateSchemaIfModelChanges<T> : IDatabaseInitializer<T> where T : DbContext
{
    private EdmMetadata _edmMetaData; 

    private bool CompatibleWithModel(string modelHash, DbContext context, ObjectContext objectContext)
    {
        if (objectContext.ExecuteStoreQuery<int>("Select COUNT(*) \r\n              FROM INFORMATION_SCHEMA.TABLES T \r\n              Where T.TABLE_NAME = 'EdmMetaData'", new object[0]).FirstOrDefault<int>() == 1)
        {
            this._edmMetaData = context.Set<EdmMetadata>().FirstOrDefault<EdmMetadata>();
            if (this._edmMetaData != null)
            {
                return (modelHash == this._edmMetaData.ModelHash);
            }
        }
        return false;
    }

    private static string ComputeSha256Hash(string input)
    {
        byte[] buffer = new SHA256Managed().ComputeHash(Encoding.ASCII.GetBytes(input));
        StringBuilder builder = new StringBuilder(buffer.Length * 2);
        foreach (byte num in buffer)
        {
            builder.Append(num.ToString("X2", CultureInfo.InvariantCulture));
        }
        return builder.ToString();
    }

    private void CreateTables(ObjectContext objectContext)
    {
        string commandText = objectContext.CreateDatabaseScript();
        objectContext.ExecuteStoreCommand(commandText, new object[0]);
    }

    private string GetCsdlXmlString(ObjectContext context)
    {
        if (context != null)
        {
            ReadOnlyCollection<EntityContainer> items = context.MetadataWorkspace.GetItems<EntityContainer>(DataSpace.SSpace);
            if (items != null)
            {
                EntityModelSchemaGenerator generator = new EntityModelSchemaGenerator(items.FirstOrDefault<EntityContainer>());
                StringBuilder output = new StringBuilder();
                XmlWriter writer = XmlWriter.Create(output);
                generator.GenerateMetadata();
                generator.WriteModelSchema(writer);
                writer.Flush();
                return output.ToString();
            }
        }
        return string.Empty;
    }

    private string GetModelHash(ObjectContext context)
    {
        return ComputeSha256Hash(this.GetCsdlXmlString(context));
    }

    public void InitializeDatabase(T context)
    {
        ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
        string modelHash = this.GetModelHash(objectContext);
        if (!this.CompatibleWithModel(modelHash, context, objectContext))
        {
            this.DeleteExistingTables(objectContext);
            this.CreateTables(objectContext);
            this.SaveModelHashToDatabase(context, modelHash, objectContext);
            this.Seed(context);
        }
    }

    private void SaveModelHashToDatabase(T context, string modelHash, ObjectContext objectContext)
    {
        if (this._edmMetaData != null)
        {
            objectContext.Detach(this._edmMetaData);
        }
        this._edmMetaData = new EdmMetadata();
        context.Set<EdmMetadata>().Add(this._edmMetaData);
        this._edmMetaData.ModelHash = modelHash;
        context.SaveChanges();
    }

    private void DeleteExistingTables(ObjectContext objectContext)
    {
        var dropConstraintsScript =
            @"declare @cmd varchar(4000)
declare cmds cursor for 
           select  'ALTER TABLE ' + so.TABLE_NAME + ' DROP CONSTRAINT ' +         
so.constraint_name  from INFORMATION_SCHEMA.TABLE_CONSTRAINTS so order by  
so.CONSTRAINT_TYPE
open cmds
while 1=1
   begin
      fetch cmds into @cmd   
          if @@fetch_status != 0 break
                           print @cmd
                           exec(@cmd)
   end
close cmds
            deallocate cmds";
        string dropTablesScript =
            @"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";
        objectContext.ExecuteStoreCommand(dropConstraintsScript);
        objectContext.ExecuteStoreCommand(dropTablesScript);
    }

}
}

答案 2 :(得分:0)

是针对EF6构建的,但对于该问题仍然是好的DbInitializer:

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Data.Entity.Migrations;

namespace MyProject.Models
{
public class MrSaleDbInitializer :
    //System.Data.Entity.DropCreateDatabaseIfModelChanges<MrSaleDbContext>
    System.Data.Entity.DropCreateDatabaseAlways<MrSaleDbContext>
{

    /*
     * Seed: Don't delete the current db, don't delete any tables, but clear all rows data in current 
     * db-tables, then seed the db with a new initial data.
     * note: Won't clear any Migration like tables or any AspNet tables such as: __MigrationHistory, AspNetUsers, AspNetRoles.
     */
    protected override void Seed(MrSaleDbContext context)        
    {
        this.ClearDb(context);
        this.SeedAfterClearingDb(context);
        base.Seed(context);         
    }


    private void ClearDb(MrSaleDbContext context)
    {
        //Optional: disable all foreign keys (db-schema will be loosed).
        //context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable @command1 = 'ALTER TABLE ? NOCHECK CONSTRAINT all'");

        List<string> tableNames = context.Database.SqlQuery<string>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME NOT LIKE '%Migration%' AND TABLE_NAME NOT LIKE 'AspNet%'").ToList();

        for (int i = 0; tableNames.Count > 0; i++)
        {
            try
            {
                //To delete all tables and not just clean them from data, replace "DELETE FROM {0}" in "DROP TABLE {0}":
                context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableNames.ElementAt(i % tableNames.Count)));

                tableNames.RemoveAt(i % tableNames.Count);
                i = -1; //flag: a table was removed. in the next iteration i++ will be the 0 index.
            }
            catch (System.Data.SqlClient.SqlException e)   // ignore errors as these are expected due to linked foreign key data    
            {
                //throw new Exception("Unable to clear any relevant table in data-base (due to foriegn key constraint ?). See inner-exception for more details.", e);
                if ((i % tableNames.Count) == (tableNames.Count - 1))
                {
                    //end of tables-list without any success to delete any table, then exit with exception:
                    throw new System.Data.DataException("Unable to clear all relevant tables in database (foriegn key constraint ?). See inner-exception for more details.", e);
                }

            }

        }

        context.SaveChanges();
    }


    /*
     * SeedAfterClearingDb: seed the data-base with initial date after database was created. 
     */
    public void SeedAfterClearingDb(MrSaleDbContext context)
    {
        //seed the data-base with initial date after database was created. 

        //then...

        //update all posts and save changes:

        context.SaveChanges();

    }
}

}