在EF6中更改数据库架构的最简洁方法

Ale*_*dar 4 oracle entity-framework-6

目前我们正在用mvc5编写一个页面,其中一个oracle sql数据库与entitiy framework 6相连.

我们目前在oracle数据库中有两个模式,一个用于测试,另一个用于开发.权利框架中的模型是从开发数据库生成的,并与之完美地协同工作.

将连接字符串更改为测试模式时出现问题.更改连接字符串后,应用程序无法找到表(因为它们仍然引用开发方案).

目前我可以通过删除模型中的所有表,并从正确的模式重新创建模型,或手动编辑引用模式的每个文件来解决此问题.这两种解决方案都有点烦人且容易出错.

这种情况通常如何处理?

编辑

似乎更改数据库并保留架构,不会产生任何错误.所以这只是架构相关的.

Ger*_*old 5

通过实体框架代码优先中的流畅映射,您可以在运行时指示默认架构。这是OnModelCreating您的DbContext子类中的一条语句,例如:

modelBuilder.HasDefaultSchema("dev");
Run Code Online (Sandbox Code Playgroud)

您习惯于从数据库重新生成模型,从中我得出结论,该模型不包含许多(或任何)定制,这些定制会使模型生成成为一项艰苦的操作。这也应该使得转向代码优先变得相对容易。所以我建议你这样做。

在 Visual Studio 中,您可以通过从 Visual Studio 实体框架工具附带的模板添加“ADO.Net 实体数据模型”,从现有数据库生成代码优先模型。(可能是预安装的)。选择选项“Code First from database”并遵循指南。

如果这样做,您将在包含模型的项目中找到一个连接字符串。该连接字符串可以用作您将放入执行程序集的配置文件中的连接字符串的模板。你会发现它看起来并不像...

metadata=res://* ... provider=System.Data.SqlClient;provider connection string="...""

这是属于数据库优先 edmx 模型的连接字符串。它包含作为程序集资源生成的元数据文件的路径。相反,连接字符串将是一个简单的 ADO.Net 连接字符串。通过代码优先,EF 将在运行时生成元数据。

如果您有这个,您可以在配置文件中为默认数据库架构添加一个条目,并使用它来设置架构,如我上面所示。


Ten*_*giz 5

我想这是使用实体框架命令拦截器的完美用例.我只是尝试过,它的工作完美,即使对于Entity Framework DB-First方法也是如此.

您可以像这样注册自定义命令拦截器:

DbInterception.Add(new ReplaceSchemaInterceptor(newSchema: "[my]"));
Run Code Online (Sandbox Code Playgroud)

在查询到达数据库之前,此行将使用[dbo]模式名称替换模式名称[my].幸运的是,当Entity Framework生成命令文本时,模式名称用方括号括起来,因此很容易匹配和替换.顺便说一下,我不是Oracle专家,所以我假设Oracle查询还包含相同格式的模式.如果没有,那么也许你将不得不稍微调整一下实现(从EF生成的任何格式替换模式).

ReplaceSchemaInterceptor是一个实现IDbCommandInterceptor接口的类.在此类中,您需要使用自己的架构替换架构.下面是这个类的实现:

class ReplaceSchemaInterceptor : IDbCommandInterceptor 
{
    private readonly string _newSchema;

    public ReplaceSchemaInterceptor(string newSchema)
    {
        _newSchema = newSchema;
    }

    public void NonQueryExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }

    public void NonQueryExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        command.CommandText = command.CommandText.Replace("[dbo]", _newSchema);
    }

    public void ReaderExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
    {
    }

    public void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
    {
        command.CommandText = command.CommandText.Replace("[dbo]", _newSchema);
    }

    public void ScalarExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
    }

    public void ScalarExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        command.CommandText = command.CommandText.Replace("[dbo]", _newSchema);
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,代码并不完美.您需要为构造函数参数添加一些空值检查,并且在替换命令文本时可能会删除实现方法中的代码重复(提取到可重用的方法?).现在它只是做你要求的.