SqlClient对象的封装与有序化
Encapsulating and Disposing SqlClient Objects In Order
我正在尝试对我的 Sql 客户端对象调用进行分层,以便可靠地处理它们。像这样:
Open database connection -> Create command -> Read results -> close
command -> close database connection
到目前为止,当我用相同的方法完成所有这些事情时,这已经成功了。
问题是这很容易出错。读起来一团糟。
当我尝试创建一个通用方法来处理此问题以清理所有内容时,returns reader 连接在 reader 启动之前关闭。
//closes connection before it can be read...apparently the reader doesn't actually have any data at that point ... relocating to disposable class that closes on dispose
public SqlDataReader RunQuery(SqlCommand command)
{
SqlDataReader reader = null;
using (var dbConnection = new SqlConnection(_dbConnectionString))
{
try
{
dbConnection.Open();
command.Connection = dbConnection;
reader = command.ExecuteReader(); // connection closed before data can be read by the calling method
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
dbConnection.Close();
}
}
return reader;
}
我可以通过创建自己的 class 实现 IDispose(等)来解决这个问题,但是当我用相同的 using 语句包装它时,它占用的行数与数据库连接 using 语句一样多。
我如何在处理所有这些工件并关闭连接的可重复 class 中处理数据库连接?
您可以创建一个 class 来保存可重复使用的开放数据库连接,但我建议将数据读入列表并返回结果:
public List<object> RunQuery(SqlCommand command)
{
List<object> results = new List<object>();
using (var dbConnection = new SqlConnection(_dbConnectionString))
{
try
{
dbConnection.Open();
command.Connection = dbConnection;
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// Repeat for however many columns you have
results.Add(reader.GetString(0));
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
return results;
}
我不知道你的数据结构,但重要的一点是你需要在处理连接之前读取你的数据(reader.GetString
这样做)。您可以找到有关如何正确读取数据的更多信息 here。
编辑:如前所述,我删除了您的 finally
声明。这是因为您的 using
语句本质上是在做同样的事情。您可以将 using
语句视为 try
-finally
块。在退出 using
语句后,您的一次性对象将始终被处理。
so there's no way to make a reusable method that tucks away all/most of the nested using statements?
支持从方法返回 DataReader 的特定模式,如下所示:
static IDataReader GetData(string connectionString, string query)
{
var con = new SqlConnection(connectionString);
con.Open();
var cmd = con.CreateCommand();
cmd.CommandText = query;
var rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return rdr;
}
然后你可以在using
块中调用这个方法:
using (var rdr = GetData(constr, sql))
{
while (rdr.Read())
{
//process rows
}
} // <- the DataReader _and_ the connection will be closed here
我正在尝试对我的 Sql 客户端对象调用进行分层,以便可靠地处理它们。像这样:
Open database connection -> Create command -> Read results -> close command -> close database connection
到目前为止,当我用相同的方法完成所有这些事情时,这已经成功了。
问题是这很容易出错。读起来一团糟。
当我尝试创建一个通用方法来处理此问题以清理所有内容时,returns reader 连接在 reader 启动之前关闭。
//closes connection before it can be read...apparently the reader doesn't actually have any data at that point ... relocating to disposable class that closes on dispose
public SqlDataReader RunQuery(SqlCommand command)
{
SqlDataReader reader = null;
using (var dbConnection = new SqlConnection(_dbConnectionString))
{
try
{
dbConnection.Open();
command.Connection = dbConnection;
reader = command.ExecuteReader(); // connection closed before data can be read by the calling method
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
dbConnection.Close();
}
}
return reader;
}
我可以通过创建自己的 class 实现 IDispose(等)来解决这个问题,但是当我用相同的 using 语句包装它时,它占用的行数与数据库连接 using 语句一样多。
我如何在处理所有这些工件并关闭连接的可重复 class 中处理数据库连接?
您可以创建一个 class 来保存可重复使用的开放数据库连接,但我建议将数据读入列表并返回结果:
public List<object> RunQuery(SqlCommand command)
{
List<object> results = new List<object>();
using (var dbConnection = new SqlConnection(_dbConnectionString))
{
try
{
dbConnection.Open();
command.Connection = dbConnection;
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// Repeat for however many columns you have
results.Add(reader.GetString(0));
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
return results;
}
我不知道你的数据结构,但重要的一点是你需要在处理连接之前读取你的数据(reader.GetString
这样做)。您可以找到有关如何正确读取数据的更多信息 here。
编辑:如前所述,我删除了您的 finally
声明。这是因为您的 using
语句本质上是在做同样的事情。您可以将 using
语句视为 try
-finally
块。在退出 using
语句后,您的一次性对象将始终被处理。
so there's no way to make a reusable method that tucks away all/most of the nested using statements?
支持从方法返回 DataReader 的特定模式,如下所示:
static IDataReader GetData(string connectionString, string query)
{
var con = new SqlConnection(connectionString);
con.Open();
var cmd = con.CreateCommand();
cmd.CommandText = query;
var rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return rdr;
}
然后你可以在using
块中调用这个方法:
using (var rdr = GetData(constr, sql))
{
while (rdr.Read())
{
//process rows
}
} // <- the DataReader _and_ the connection will be closed here