1

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

我的问题是我的班级需要获取连接字符串,但我希望用户提供它。基本上,我不希望它仅限于配置文件。到目前为止,这是我的想法:

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

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

4

2 回答 2

2

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

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

于 2012-12-28T20:15:16.787 回答
1

与 usr 半同意,无论你走哪条路,你都需要创建一个 IConnectionProvider。

但是,我认为这取决于您希望允许开发人员使用您的课程有多大的灵活性。

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

您是否想提醒开发人员并让他们在您的类状态发生变化时灵活地更改连接?如果是这样,那么提供事件可能是一个不错的选择。

您的类是静态的还是您想强制开发人员提供与方法调用不同的连接?然后,每个方法都应采用 IConnectionProvider。

你需要决定你想为你的班级提供多大的灵活性,并据此做出选择。

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

编辑:这是我为合并连接代码所做的示例。

    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 映射您的对象并提供一种自动转换它们的方法,但就我而言,我无法依赖它。

于 2012-12-28T20:56:34.727 回答