如何向与数据库接口的类提供连接字符串

本文关键字:连接 字符串 接口 数据库 | 更新日期: 2023-09-27 17:49:43

我正在尝试c#中的数据访问。我正在编写一个类,它有一个Save(object o)方法,它将循环遍历每个对象的属性,并使用属性将它们与数据库匹配。

我的问题是,我的类需要获得连接字符串,但我希望用户提供它。我不希望它被限制在一个配置文件,基本上。以下是我目前想到的:

  • 在每次连接之前触发一个事件,用户将通过自定义EventArgs类提供字符串(类似于如何向ASP提供自己的对象实例)。. NET ObjectDataSource通过ObjectCreating事件)
  • 我的数据访问类
  • 中的属性
  • 两者的组合,如果事件没有订阅者,则使用属性值

我只是想知道还有什么其他的可能性,在这种情况下最好的策略是什么?

如何向与数据库接口的类提供连接字符串

事件是不自然的,因为如果不是只有一个订阅者存在,代码就会中断。事件用于订阅者的数量与引发事件的类无关的用例。

使用属性或接口(如IConnectionProvider)注入连接字符串。接口版本适合与DI容器一起使用。

半同意usr的观点,无论你选择哪种方式,你都需要创建一个IConnectionProvider

然而,我认为这取决于你想让开发人员对你的类有多大的灵活性。

你会强迫你的类的每个实例都有一个全局连接,这个连接将保持不变,并用于所有需要访问db的方法调用吗?如果是这样,那么你的类需要在它的构造函数中使用IConnectionProvider。

当你的类的状态改变时,你想提醒开发人员并给他们灵活性来改变连接吗?如果是这样,那么提供Event可能是一个不错的选择。

你的类是静态的还是你想强迫开发人员通过方法调用提供不同的连接?然后,每个方法都应该接受一个IConnectionProvider。

你需要决定你的类有多大的灵活性,并在此基础上做出选择。

如果你想允许极大的灵活性和自定义,你可能需要研究lambda表达式。使用它们,您可以允许开发人员提供一个方法,您将在代码中的某个点调用该方法。使用lambda表达式,我能够通过编写通用数据库方法来整合代码,其中调用者只需要提供代码来读取我为其设置的IDataReader,并处理捕获任何异常以及关闭和处置所需的任何数据库对象。

EDIT:下面是我合并连接代码的示例。

    public static T ExecuteReader<T>(IDbConnection connection, string commandText, Func<IDataReader, T> readData) where T : class
    {
        IDbCommand command = connection.CreateCommand();
        command.CommandText = commandText;
        try
        {
            connection.Open();
            IDataReader reader = command.ExecuteReader();
            T returnValue = readData(reader); //Call the code provided by the caller and get the return object.
            reader.Close();
            reader.Dispose();
            return returnValue; //Return their return object.
        }
        finally
        {
            if (command != null)
            {
                command.Dispose();
            }
            if (connection != null)
            {
                try
                {
                    if (connection.State != ConnectionState.Closed)
                    {
                        connection.Close();
                    }
                }
                finally
                {
                    connection.Dispose();
                }
            }
        }
    }

使用例子:

MyDataList.AddRange(
    Database.ExecuteReader<List<MyDataModel>>( //Tell ExecuteReader what type of object to return
    connection, //Pass in the connection
    commandString, //Pass in the command
    delegate(IDataReader reader) //This code is called from inside the ExecuteReader method.
    {
        List<MyDataModel> List = new List<MyDataModel>();
        while (reader.Read())
        {
            //Read each record, transform it into MyDataModel, then add it to the List.
        }
        return List;
    }
}));
之所以创建泛型ExecuteReader方法,是因为用于创建命令、打开连接和处理所有连接的代码保持不变,并为每个对象复制。这可以防止不必要的代码复制。唯一真正改变的是如何将对象从IDataReader转换为类,以便ExecuteReader方法的调用者能够提供执行特定转换的代码。

这对你来说可能不是真的,因为你是1:1映射你的对象,并提供一种自动转换它们的方法,但在我的情况下,我不能依赖于这一点。