我正在尝试在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编写数据库脚本,并针对目标数据库运行它?
答案 0 :(得分:2)
查看David.Cline(开发)博客,了解“在模型更改时删除并创建表”:
http://www.davidcline.info/2012/05/technologies-c-v4.html
此链接可能会有所帮助:
谢谢, 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();
}
}
}