我试图在用户登录网站时获取用户信息,当我使用DataSet
时成功,但如果我想使用SqlDataReader
,则错误显示:{ {1}}。我有搜索为什么会这样,我发现一篇文章说
Invalid attempt to read when reader is closed
要求连接保持打开才能获得 来自服务器的数据,而SqlDataReader
不需要 连接仍然是开放的。
我的问题是:我想知道如何使用DataSet
?因此,当我想从数据库中获取数据时,我不必依赖SqlDataReader
。
当我尝试使用DataSet
更改读取数据函数的结构时,会出现问题,因此可以随时重复使用。
以下是代码:
DatabaseManager类:
SqlDataReader
网络管理员课程:
public SqlDataReader GetInformationDataReader(string procName, SqlParameter[] parameters)
{
SqlDataReader reader = null;
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(procName, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
if (parameters != null)
{
foreach(SqlParameter parameter in parameters)
{
cmd.Parameters.Add(parameter);
}
}
reader = cmd.ExecuteReader();
}
}
return reader;
}
控制器:
public ModelContexts.InformationContext GetInformation(string username)
{
SqlDataReader reader = null;
ModelContexts.InformationContext context = new ModelContexts.InformationContext();
SqlParameter[] parameters =
{
new SqlParameter("@Username", SqlDbType.NVarChar, 50)
};
parameters[0].Value = username;
try
{
reader = DatabaseManager.Instance.GetInformationDataReader("GetInformation", parameters);
while(reader.Read())
{
context.FirstName = reader["FirstName"].ToString();
context.LastName = reader["LastName"].ToString();
context.Email = reader["Email"].ToString();
}
}
catch(Exception ex)
{
throw new ArgumentException(ex.Message);
}
return context;
}
Model包含带有getter和setter的字符串返回值(FirstName,LastName和Email)。
View包含html标签,并对Model中的FirstName,LastName和Email进行编码。
感谢您的回答。
感谢。
答案 0 :(得分:2)
这是一种可用于保持代码非常干净的方法,允许您在连接仍处于打开状态时从SqlDataReader
读取。它利用了传递代表的优势。希望代码是可以理解的。您可以调整它以满足您的特定需求,但希望它可以为您提供另一种选择。
public void GetInformationDataReader(string procName, SqlParameter[] parameters, Action<SqlDataReader> processRow)
{
SqlDataReader reader = null;
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(procName, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
if (parameters != null)
{
foreach(SqlParameter parameter in parameters)
{
cmd.Parameters.Add(parameter);
}
}
using (SqlDataReader dataReader = cmd.ExecuteReader())
{
while (dataReader.Read())
{
// call delegate here.
processRow(dataReader);
}
}
}
}
return reader;
}
public ModelContexts.InformationContext GetInformation(string username)
{
SqlDataReader reader = null;
ModelContexts.InformationContext context = new ModelContexts.InformationContext();
SqlParameter[] parameters =
{
new SqlParameter("@Username", SqlDbType.NVarChar, 50)
};
parameters[0].Value = username;
try
{
// Instead of returning a reader, pass in a delegate that will perform the work
// on the data reader at the right time, and while the connection is still open.
DatabaseManager.Instance.GetInformationDataReader(
"GetInformation",
parameters,
reader => {
context.FirstName = reader["FirstName"].ToString();
context.LastName = reader["LastName"].ToString();
context.Email = reader["Email"].ToString();
});
}
catch(Exception ex)
{
throw new ArgumentException(ex.Message);
}
return context;
}
简要说明:
您会注意到代码的整体结构与您已有的非常相似。唯一的变化是:
SqlDataReader
,GetInformationDataReader()
方法 接受 Action<SqlDataReader>
代表。GetInformationDataReader()
方法中,在正确的时间调用委托,而连接仍处于打开状态。GetInformationDataReader()
的调用,以作为代理传递代码块。这种模式对于这些情况非常有用。它使代码可重用,它使它非常干净和分离,并且它不会阻止您从using
构造中受益以避免资源/连接泄漏。
答案 1 :(得分:1)
您已将SqlConnection
对象包装在using
子句中,因此在其SqlConnect.Dispose
结束时调用,关闭连接。无论呼叫者消费的是哪个SqlDataReader
都不再具有开放式连接,因此您就会收到错误。
而DataSet不需要连接保持打开状态。
这不完全正确。 DataSet
只是在SqlDataAdapter
(该类的Fill()
方法)调用时通常填充的对象。 SqlDataAdapter
处理SqlConnection
的开启和关闭,这很可能就是为什么评论会说明这一点。但它处理的是一个不同的类,而不是DataSet
本身。可以将DataSet
视为包含SqlCommand
的结果集的对象。
回答您的评论......
那么,我不应该使用关键字来解决这个问题吗?在所有的Sql关键字中?
我也不会采取这种方法。你可以很容易地使用该模型获得连接泄漏错误,并且用尽排除连接可能是一个不太有趣的问题。
通常最好使用您的数据,然后关闭/处置您的连接。有一种说法,&#34;开放晚,早关闭&#34;。 通常您希望如何处理此问题。对于您正在处理的这个问题,我不会尝试在类方法之间传递SqlDataReader
对象。解决方法(保持连接打开)非常容易出错。
另一个过程,回到我们提到的事情,不要使用SqlDataReader
。循环读取每一行没有任何好处。根据您的结果集,只需填写DataSet
(或通常更合适,DataTable
),然后返回Data[Set | Table]
,或者更好地返回更能代表数据的对象它属于。