连接关闭后有没有办法访问SqlDataReader
?
或者是否有任何等同于SqlDataReader
的对象我可以将阅读器存储到它们中并在以后对这些对象进行处理?
我从服务器接收了一个数据透视数据集,因此我无法使用普通类来处理这类数据,我的模型如下所示:
public class OneToNinetyNine
{
public List<Cities> listCities;
public string CityID;
public DateTime DateFrom;
public DateTime DateTo;
// this is the reader that I attempt to pass to the views
public SqlDataReader SqlReader;
}
答案 0 :(得分:4)
关闭连接后,您无法使用DataReader
,因为它需要使用连接从数据源检索数据。
您需要使用DataSet
方法将数据读入DataTable
或Load
,然后才能关闭连接。
答案 1 :(得分:4)
您可以将SqlDataAdapter
中的数据存储到DataSet
中以备将来使用:
DataSet ds = new DataSet();
SqlCommand mycommand = new SqlCommand("sql statement");
using (SqlDataAdapter adapter = new SqlDataAdapter(mycommand))
{
adapter.Fill(ds);
}
答案 2 :(得分:1)
连接关闭后有没有办法访问SqlDataReader?
没有。关闭连接后,阅读器无法从连接中读取数据。
但是,通过DataReader
或Connection
来电ExecuteReader
,可以将ExecuteReaderAsync
和CommandBehavior.CloseConnection
之间的关系生命周期反转1}}指定。在此模式下,当Reader关闭(或处置)时,Connection将关闭。
如果您不一定想要一次性检索和实现查询中的所有数据,那么使用CommandBehavior.CloseConnection
的长寿数据读者会非常有用,例如数据分页或接收类型惰性等用例评价。这是下面的选项2。
选项1:打开连接,检索并实现所有数据,并关闭所有内容
与其他答案一样,在许多情况下,对于小的,确定的数据提取,最好打开连接,创建命令,执行读取器,并一次性获取和具体化所有数据:
public async Task<Foo> GetOneFoo(int idToFetch)
{
using (var myConn = new SqlConnection(_connectionString))
using (var cmd = new SqlCommand("SELECT Id, Col2, ... FROM Foo WHERE Id = @Id"))
{
await myConn.OpenAsync();
cmd.Parameters.AddWithValue("@Id", idToFetch);
using (var reader = await cmd.ExecuteReaderAsync())
{
var myFoo = new Foo
{
Id = Convert.ToInt32(reader["Id"]),
... etc
}
return myFoo; // We're done with our Sql data access here
} // Reader Disposed here
} // Command and Connection Disposed here
}
选项2:打开连接,执行命令,并使用Long Lived Reader
使用CommandBehavior.CloseConnection
,我们可以创建一个长期存在的读者,并推迟关闭连接,直到不再需要Reader
。
为了防止像DataReaders
这样的数据访问对象流入更高层代码,可以使用yield return
生成器来管理读者生命周期 - 同时确保读者(以及连接)一旦不再需要发电机,它就会关闭。
public async Task<IEnumerable<Foo>> LazyQueryAllFoos()
{
// NB : No `using` ... the reader controls the lifetime of the connection.
var sqlConn = new SqlConnection(_connectionString);
// Yes, it is OK to dispose of the Command https://stackoverflow.com/a/744307/314291
using (var cmd = new SqlCommand(
$"SELECT Col1, Col2, ... FROM LargeFoos", mySqlConn))
{
await mySqlConn.OpenAsync();
var reader = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection);
// Return the IEnumerable, without actually materializing Foos yet.
// Reader and Connection remain open until caller is done with the enumerable
return GenerateFoos(reader);
}
}
// Helper method to manage lifespan of foos
private static IEnumerable<Foo> GenerateFoos(IDataReader reader)
{
using(reader)
{
while (reader.Read())
{
yield return new Foo
{
Id = Convert.ToInt32(reader["Id"]),
...
};
}
} // Reader is Closed + Disposed here => Connection also Closed.
}
备注强>
async
代码当前也不能使用yield return,因此需要将helper方法从异步查询中分离出来(但是我可以相信将帮助器移动到Local Function中) GenerateFoos
的代码确实需要注意不要将Enumerable(或它的Iterator)保留的时间超过需要的时间,因为这会使底层的Reader和Connection保持打开状态。