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