如何在DontDropDbJustCreateTablesIfModelChanged之后种子数据库

时间:2012-07-25 09:38:59

标签: entity-framework-4.1 ef-code-first

最近我的数据库权限已经减少,因此我无法删除并重新创建数据库。这导致我使用nuget的DontDropDbJustCreateTablesIfModelChanged数据库初始化。

然而,由于种子功能不在初始化中,因此我无法覆盖它,因此我现在不知道应该如何播种数据。这是我希望能够做到的。

public class MyDBInitialiser : DontDropDbJustCreateTablesIfModelChanged<MyContext>
{
    protected override void Seed(MyContext context)
    {
        base.Seed(context);

        context.Item.Add(new Item() { ItemId = 1, Name = "Item 1"});
        context.Item.Add(new Item() { ItemId = 2, Name = "Item 2"});
        context.Item.Add(new Item() { ItemId = 3, Name = "Item 3"});
    }
}

在这种情况下是否存在另一种播种数据的方式。

2 个答案:

答案 0 :(得分:1)

简单地说,

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);
        Seed(context);
    }

    protected virtual void Seed(T 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(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)
            {
                var 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'";
}

&安培;

public class Population : DontDropDbJustCreateTablesIfModelChanged</* DbContext */>
{
    protected override void Seed(Syndication Context)
    {
        /* Seeding :) */
    }
}

&安培;

Database.SetInitializer</* DbContext */>(new Population());

答案 1 :(得分:0)

我的项目是我从数据库种子分割数据库初始化。如果您使用控制反转,您应该能够在合成根中执行类似的操作(如果您正在从Web应用程序中使用DbContext,则为Application_Start):

var seeder = ServiceLocatorPattern
    .ServiceProviderLocator.Current.GetService<ISeedDb>();
if (seeder != null) seeder.Seed();

界面:

public interface ISeedDb, IDisposable
{
    void Seed();
}

可能的实施:

public class MyDbSeeder : ISeedDb
{
    private readonly MyContext _context;

    public MyDbSeeder(MyContext context)
    {
        _context = context;
    }

    public void Seed()
    {
        _context.Item.Add(new Item { ItemId = 1, Name = "Item 1" });
        // ... etc
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}