Entity Framework 6 设置连接字符串运行时

Posted

技术标签:

【中文标题】Entity Framework 6 设置连接字符串运行时【英文标题】:Entity Framework 6 set connection string runtime 【发布时间】:2015-06-09 00:41:13 【问题描述】:

我们处于一个混合环境中,我们的应用程序同时使用 ADO.NET 和 Entity Framework。 由于两者都指向同一个物理 SQL 服务器,我们希望从配置文件中删除 Entity Framework 连接字符串,然后根据当前的 ADO.NET 连接字符串自动构建字符串。 这使我们避免了开发人员更改 ADO.NET 字符串但忘记更改实体框架连接字符串的错误。

我已阅读此内容,但他们没有回答问题。How do I create connection string programmatically to MS SQL in Entity Framework 6?

如果我创建自己的 DbConnection 并将其传递给 DbContext(existingConnection, contextOwnsConnection),则会引发错误“上下文正在代码优先模式下使用,代码是从数据库优先或模型的 EDMX 文件生成的第一次开发。”

我没有使用 Code First。

https://msdn.microsoft.com/en-us/data/jj680699 这谈到了 EF 6 中的代码库配置,但文章没有显示任何实际更改连接字符串的代码。

更新:更多信息有助于澄清我的问题。 我没有先使用代码,而是想在配置文件之外构建一个连接字符串。 我使用的 DbContext 是 T4 模板正在生成的自动生成的 DbContext 文件的部分类。 我的印象是我需要创建一个继承的 DbConfiguration 类并在该类中执行某些操作,但我发现的唯一示例是使用 Azure。https://msdn.microsoft.com/en-us/data/jj680699 代码项目上有一篇文章谈到了在运行时设置连接字符串,但这篇文章是基于每次创建新实体容器时构建连接字符串。http://www.codeproject.com/Tips/234677/Set-the-connection-string-for-Entity-Framework-at

我希望能够使用我的部分 DbContext 类来创建连接字符串,这样调用者就不必做任何特殊的事情。

更新:RunTime 的工作代码,但 DesignTime 的工作代码 使用@Circular Reference“下面列出”发布的代码,我能够在不更改对我的实体类的调用的情况下更改连接字符串,但这不适用于 DesignTime EDMX 文件。

public partial class TestEntities : DbContext

    public TestEntities() : base(GetSqlConnection(), true)
    
    

    public static DbConnection GetSqlConnection()
    
        // Initialize the EntityConnectionStringBuilder. 
        EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();

        var connectionSettings = ConfigurationManager.ConnectionStrings("Current_ADO_Connection_In_Config");

        // Set the provider name. 
        entityBuilder.Provider = connectionSettings.ProviderName;

        // Set the provider-specific connection string. 
        entityBuilder.ProviderConnectionString = connectionSettings.ConnectionString;

        // Set the Metadata location. 
        entityBuilder.Metadata = "res://*/Models.TestModel.csdl|res://*/Models.TestModel.ssdl|res://*/Models.TestModel.msl";

        return new EntityConnection(entityBuilder.ToString());
    

现在,如果我能让 DesignTime 正常工作,那就太好了。

【问题讨论】:

我认为您将使用 ObjectContext 而不是 DbContext,因为您没有使用 Code First。我对这段关系不是 100% 确定的。这暗示了这一点:msdn.microsoft.com/en-us/library/bb738461(v=vs.110).aspx 并从此处链接描述创建连接:msdn.microsoft.com/en-us/library/… CodeFirst 的连接字符串通常是标准连接字符串,而非 CodeFirst 的连接字符串通常是对 csdl/ssdl/msl 文件的引用。 可以使用ObjectContext,但是如果你不需要深入研究它的特殊属性,那就很麻烦了。从 EF 5 开始,使用 DbContext 是正常的。 EntityConnection 是常规连接字符串的超集,具有访问 EDMX 文件的概念和存储部分的附加属性。 【参考方案1】:

您可以在设计时使用配置文件中的连接字符串。

<add name="DWContext" connectionString="metadata=res://*/Database.DWH.DWModel.csdl|res://*/Database.DWH.DWModel.ssdl|res://*/Database.DWH.DWModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=SQLSERVER_INSTANCE;initial catalog=DB_NAME;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

所以不要删除它,因为您只在设计时需要它。

使用这种方法在运行时以动态方式工作(类似于您的上一种方法):

扩展数据上下文分部类:

public partial class DWContext

    public DWContext(string nameOrConnectionString)
        : base(nameOrConnectionString)
    
    

    /// <summary>
    /// Create a new EF6 dynamic data context using the specified provider connection string.
    /// </summary>
    /// <param name="providerConnectionString">Provider connection string to use. Usually a standart ADO.NET connection string.</param>
    /// <returns></returns>
    public static DWContext Create(string providerConnectionString)
    
        var entityBuilder = new EntityConnectionStringBuilder();

        // use your ADO.NET connection string
        entityBuilder.ProviderConnectionString = providerConnectionString;

        entityBuilder.Provider = "System.Data.SqlClient";

        // Set the Metadata location.
        entityBuilder.Metadata = @"res://*/Database.DWH.DWModel.csdl|res://*/Database.DWH.DWModel.ssdl|res://*/Database.DWH.DWModel.msl";

        return new DWContext(entityBuilder.ConnectionString);
    


然后从您的代码中创建一个新的 EF 数据上下文:

private DWContext db = DWContext.Create(providerConnectionString);

Ciao ;-)

【讨论】:

这对我不起作用,我收到“此上下文正在代码优先模式下使用...”消息。 @NilsGuillermin 尝试删除并再次创建数据模型,并确保选择“从现有数据库创建(数据库优先)”选项。 @jacktric我没有那个选项,我想要的是“数据库中的代码优先”和“数据库中的 EF 设计器”吗? @jacktric,我喜欢这种架构/解决方案的优雅。但是,当我尝试使用它时,编译器无法编译构造函数。 public DWContext(string nameOrConnectionString) : base(nameOrConnectionString) 错误是基类不接受任何参数。 不错的解决方案。值得指出的是,在扩展数据上下文分部类时,应将该段代码(如上所示)放入单独的文件中,因为原始文件是由 Visual Studio 自动生成的。这就是关键字 partial 存在的原因。【参考方案2】:

您将收到 Code First 模式异常,因为您正在传递使用 ADO.NET 连接字符串构建的 DbConnection。此连接字符串不包含对元数据文件的引用,因此 EntityFramework 不知道在哪里可以找到它们。

要使用适当的以编程方式设置的连接字符串创建DbContext,请使用EntityConnectionStringBuilder 类。

var entityBuilder = new EntityConnectionStringBuilder();

// use your ADO.NET connection string
entityBuilder.ProviderConnectionString = conString;

// Set the Metadata location.
entityBuilder.Metadata = @"res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl";
var dbContext = new DbContext(entityBuilder.ConnectionString);

【讨论】:

您的答案有效,但每次我在代码中创建实体容器时都必须这样做。我需要一些在部分 DbContext 调用中执行此操作的方法……但即便如此,我也不确定这是否适用于设计器。我想我必须对 DbConfiguration 做点什么,但我找不到任何好的例子。 检查this。您将不得不编写更多代码,虽然它可以工作,但从可维护性的角度来看并不好。最好将 EF 连接字符串保留在配置文件中。 如果我可以开始工作,我会接受这个实现。但是,在尝试访问由上述创建的数据库上下文数据库时,我收到“关键字不支持'元数据'”的错误。【参考方案3】:

另一种方法是在配置文件中声明另一个连接字符串并将其与以下替代构造函数一起使用:

class TestEntities : DbConnect 
 
    public TestEntities (string connectionName)
       : base($"name=connectionName")
    
    

...

然后使用这个解决方案:

    向配置文件添加另一个连接:
 <add name="other" connectionString="metadata=res://*/Data.TestEntities .csdl|res://*/Data.TestEntities .ssdl|res://*/Data.TestEntities .msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=...;initial catalog=...;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

    这样称呼它:

    var db = new TestEntities (connectionName:"other");
    

【讨论】:

以上是关于Entity Framework 6 设置连接字符串运行时的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 Windows Azure(预览版)管理门户设置 ADO.NET Entity Framework 连接字符串?

Entity Framework 6 的动态 MySQL 数据库连接

在 Entity Framework 6 中使用 MySQL 和 MSSQL

如何用Entity Framework 6 连接Sqlite数据

Entity Framework 6 和 SQL Server CE,代码优先

如何使用 Entity Framework 6 Code First 设置默认值约束?