如何让用户在c# EF4.1代码优先中动态指定数据库提供者和连接细节

本文关键字:动态 数据库 提供者 细节 连接 用户 代码 EF4 | 更新日期: 2023-09-27 18:06:15

我正在创建一个c#应用程序,以取代使用MySQL数据库的VB6应用程序,其中应用程序的多个副本使用相同的数据库。新的应用程序必须能够使用当前的MySQL数据库,但我也希望它是数据库不可知论,所以应用程序的未来实例可以使用用户想要的任何服务器。在一个完美的世界里,我希望在第一次运行的应用程序呈现给用户一个对话框,让他们选择数据库类型(MySQL, SQL Server等),并指定服务器ip,用户,密码和数据库名称。然后,应用程序将连接到该服务器,如果数据库已经存在,则使用该数据库;如果数据库不存在,则创建一个新数据库。

使用代码首先,我已经到了我了解如何使用现有数据库或创建一个新的点,但只能通过硬编码在App.config文件中的连接字符串。

    <add name="GumpIndexDatabase"
     connectionString="server=localhost;userid=123;password=123;port=3306;database=gump_new_data;pooling=false;"
     providerName="MySql.Data.MySqlClient"
     />

我可以在启动应用程序之前更改连接字符串和提供商,一切都按预期工作。我也可以在启动后更改连接字符串,但不是提供者,我必须知道提供者是MySQL还是MSSQL,以便获得正确的连接字符串详细信息(例如:user或userid)

class GumpIndexDatabase: DbContext
{
    public GumpIndexDatabase(string connectionName)
        : base(MakeConnectionString(connectionName))
    {
    }
    private static string MakeConnectionString(string connectionName)
    {
         if (connectionName=MySQL) {
             //return MySQL string
         } else {
             //return SQL Server string
         }
    }

几个小时的搜索没有找到一个如何做这样的事情的例子,所以我怀疑这是不允许或不推荐的,即使它看起来像这样一个简单的事情。我看过一些关于连接字符串生成器的文章,但不明白如何从通用对象中获得数据库特定的字符串。

那么简单的问题是:如何在运行时指定数据库连接细节?

如何让用户在c# EF4.1代码优先中动态指定数据库提供者和连接细节

我不建议强制执行这个功能,除非你100%肯定你不能没有它。它增加了许多维护任务,这些任务可能现在还不明显(比如更新到新版本、修复错误、花费大量时间找出通用接口、维护这些接口、大量测试等)。所以,除非它是一个被要求的业务功能-忘记它。

然而,如果你知道你在做什么,这个问题通常通过接口来解决。可能有这些公共接口(找出它们本身就是一项任务):

  • IConnection
  • IDataProvider
  • IRepository<T>

目前,您将使用MySql数据库实现接口,例如class MySqlConnection : IConnection。如果您需要MS SQL,请使用class MsSqlConnection : IConnection

你必须有效地将所有的功能抽象到公共接口中。您必须为希望支持的每个数据库/存储引擎提供实现。在运行时,您将使用IoC容器和DI原则来设置当前实现。所有的子依赖将使用接口作为参数传递给构造函数(或属性或方法)

您是否尝试了Database属性?

GumpIndexDatabase.Database.Connection.ConnectionString = "your conn string";

我刚刚测试了它非常短的,所以不能保证它没有问题。但是我成功地在我的一个服务层类的构造函数中使用了它:

public class MyService
{
    protected DataContext DataContext { get; set; }
    public MyService(DataContext dataContext)
    {
        DataContext = dataContext;
        DataContext.Database.Connection.ConnectionString = "conn string";
    }
}

刚才看到DbContext有一个重载DbContext(string nameOrConnectionString)。你应该也能使用这个。

使用现有连接

或者使用现有连接。你的DbContext应该是这样的:

public class DataContext : DbContext
{
    public DataContext(DbConnection existingConnection)
        : base(existingConnection, true) { }
}

然后在你需要的地方初始化它:

public void SomeMethod()
{
    var connString = "whatever"; // could also be something like Textbox1.Text
    using (var connection = new SqlConnection(connString))
    {
        var context = new DataContext(connection);
    }
}

当然SqlConnection可以是继承自DbConnection的任何元素。