Mar*_*ark 27 entity-framework code-first ctp4
我想实现一个自定义数据库初始化策略,以便我可以使用提供的用户ID和密码生成数据库模式并将其应用于EXISTING EMPTY SQL数据库.
不幸的是,内置策略没有提供我正在寻找的东西:
// 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>());
Run Code Online (Sandbox Code Playgroud)
我已经解决了以下问题,但这不会创建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();
}
}
Run Code Online (Sandbox Code Playgroud)
问题:
有谁知道如何获取/创建模型哈希?(这是一个EdmMetadata实体)
-要么-
使用Code First CTP一般有更好的方法吗?
Luh*_*ann 24
我遇到了同样的问题.我没有真正解决它,但我设法运行了一些讨厌的解决方法,所以我可以将我的解决方案部署到AppHarbor;)
它是一个IDatabaseInitializer实现,它不删除数据库,只是核对所有约束和表,然后使用ObjectContext.CreateDatabaseScript()方法生成sql,然后我将它作为storecommand执行.很像问题中的上述实现.
但我还添加了从模型创建哈希并将其保存在db中的功能,当它再次运行时,它检查当前模型哈希是否与i db匹配.就像真正的代码优先实现一样.
我无法使用上下文中的构建工作.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'";
}
}
Run Code Online (Sandbox Code Playgroud)
这是在AppHarbor上运行EF Code First的最简单方法!
使用该EdmMetadata.TryGetModelHash(context)函数检查模型何时与数据库不匹配,并在运行更改脚本后显示需要使用的新代码的错误.
我以为我会发布我自己的初始化程序版本,我目前正在appharbor上使用它来填充现有数据库.如果数据库不存在,它也会尝试进行创建,如果检测到更改则抛出它(抱歉没有自动更新).我希望有人发现它有用.
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";
}
}
Run Code Online (Sandbox Code Playgroud)
只是为@ 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'";
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
14259 次 |
| 最近记录: |