C# 跨n层保持SqlDataReader打开
我有一个数据库类,它抽象了SqlCommand的ExecuteOnQuery和ExecuteReader。由于使用块包装Sqlconnection和SqlCommand,因此在调用CustomExecuteReader后SqlDataReader将关闭,因此我无法在业务层读取SqlReaderResultSet。代码如下。谢谢大家的反馈C# 跨n层保持SqlDataReader打开,c#,sqldatareader,C#,Sqldatareader,我有一个数据库类,它抽象了SqlCommand的ExecuteOnQuery和ExecuteReader。由于使用块包装Sqlconnection和SqlCommand,因此在调用CustomExecuteReader后SqlDataReader将关闭,因此我无法在业务层读取SqlReaderResultSet。代码如下。谢谢大家的反馈 public static SqlDataReader SqlReaderResultSet { get; set; } public static
public static SqlDataReader SqlReaderResultSet { get; set; }
public static SqlDataReader CustomExecuteReader(string storedProc)
{
using (var conn = new SqlConnection(ConnectionString))
{
var cmd = new SqlCommand(storedProc, conn) {CommandType = CommandType.StoredProcedure};
try
{
conn.Open();
SqlReaderResultSet = cmd.ExecuteReader();
}
catch (InvalidOperationException)
{
if (conn.State.Equals(ConnectionState.Closed))
conn.Open();
}
finally
{
conn.Close();
}
}
return SqlReaderResultSet;
}
我无法在业务层读取SqlReaderResultSet,您不应该这样做。应该使用数据传输对象传递数据,而不是通过低级数据访问结构。我建议更改方法,以便上面描述的方法在datareader中迭代记录,并创建对象列表。这个对象列表就是应该返回和处理的对象。迭代器块可以解决这个问题。执行以下操作是合法且通常是安全的:
IEnumerable<MyFancyData> ResultSet {
get {
using(DbConnection conn = ...)
using(DbCommand cmd = ...) {
conn.Open();
using(DbDataReader reader = cmd.ExecuteReader()) {
while(reader.Read()) {
yield return new MyFancyData(reader[0], reader[42] ...);
}
}
}
}
}
每次枚举ResultSet属性时,都会再次构造连接,然后foreach和其他IEnumerator使用者会适当地调用生成器的Dispose方法,从而允许using块执行其操作
这种方法保留了对数据读取器中项目的“随需随用”评估,当数据集变大时,这些评估可能是相关的,这仍然会从公共API中抽象出sql级别的细节。虽然我同意这个想法,添加数据传输对象意味着包含大量的样板代码,而这些代码几乎什么都不做。在这一点上,我们有理由怀疑所有这些毫无意义的代码是否都有作用。SqlDataReader作为数据结构传递不是件好事,但是区分那些健康的高级数据结构和低级数据访问结构并不总是黑白分明的,这是非常正确的。感谢您的启发。请记住,数据读取器与数据库保持实时连接。如果结果集足够小,请改用数据集。否则,这种方法会导致连接泄漏