我只是想知道从班级回来读者的正确方法吗?
我的代码可以使用,但我不确定这是否正确。
另外。我无法关闭我的类方法中的连接,仍然可以从我的ascx页面访问它,是
好吗?//在我的课程中,我有以下方法来返回记录/阅读器 - 在这种情况下它是一条记录。
public SqlDataReader GetPost()
{
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand("con_spPost", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@blogid", blogid);
try
{
conn.Open();
return cmd.ExecuteReader();
}
finally
{
// conn.Close();
}
}
//然后我在我的ascx页面中调用GetPost方法,如下所示:
protected void Page_Load(object sender, EventArgs e)
{
//instantiate our class
MyClass DB = new MyClass();
//pass in the id of the post we want to view
DB.PostID = Int32.Parse(Request.QueryString["p"]);
///call our GetPost method
SqlDataReader reader = DB.GetPost();
//output the result
reader.Read();
this.viewpost.InnerHtml = "<span id='post1_CreatedDate'>" + reader["CreatedDate"].ToString() + "</span><br>";
this.viewpost.InnerHtml += "<span class='blogheads'>" + reader["BlogTitle"].ToString() + "</span><p><p>";
this.viewpost.InnerHtml += reader["BlogText"].ToString();
reader.Close();
}
感谢您对我的代码或提示提出任何意见,谢谢。
熔体
答案 0 :(得分:6)
一般来说,从一个方法返回一个读者是可以的,但读者的消费者需要控制所有将在读者一生中使用的一次性对象。
要执行此操作,您需要将IDbConnection
传递给GetPost
方法,然后确保您的调用者同时处理连接和阅读器。 using
关键字是执行此操作的最便捷方式:
protected void Page_Load(object sender, EventArgs e) {
// Create the DB, get the id, etc.
using (IDbConnection connection = new SqlConnection(connectionString))
using (IDataReader reader = DB.GetPost(connection)) {
reader.Read();
this.viewpost.InnerHtml = reader["BlogText"].ToString();
// finishing doing stuff with the reader
}
}
正如其他人所指出的那样,这开始使用过多的数据访问基础设施使应用程序的表示层变得混乱 - 所以这里不适合。在您发现自己遇到性能问题或需要显示不合理数据量之前,您不应该在表示层中处理数据读取器。只需让DB.GetPost
返回一个字符串,并将所有数据访问代码封装在那里。
答案 1 :(得分:5)
要确保连接已关闭,请使用以下内容替换ExecuteReader
来电:
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
您还应该删除te try
/ finally
阻止。
此外,在Page_Load
处理程序中,您应该使用using
语句,如下所示:
using (SqlDataReader reader = DB.GetPost()) {
//output the result
reader.Read();
this.viewpost.InnerHtml = "<span id='post1_CreatedDate'>" + reader["CreatedDate"].ToString() + "</span><br>"
+ "<span class='blogheads'>" + reader["BlogTitle"].ToString() + "</span><p><p>"
+ reader["BlogText"].ToString();
}
此外,您应该检查SQL查询是否实际返回了一些内容,如下所示:
if (!reader.Read()) {
Something's wrong
}
最后,到目前为止最重要的,您应该通过调用Server.HtmlEncode
来转义HTML以防止XSS漏洞。
例如:
this.viewpost.InnerHtml = "<span id='post1_CreatedDate'>" + reader["CreatedDate"].ToString() + "</span><br>"
+ "<span class='blogheads'>" + Server.HtmlEncode(reader["BlogTitle"].ToString()) + "</span><p><p>"
+ Server.HtmlEncode(reader["BlogText"].ToString());
答案 2 :(得分:3)
你真的不应该将数据访问与表示层混合在一起。
考虑返回一个类型化的DataSet,或构建业务对象并将其返回给您的控件。
这是一个教程: http://www.asp.net/learn/data-access/tutorial-01-cs.aspx
答案 3 :(得分:2)
有一个问题。您的连接未被关闭。如您所知,您无法在GetPost中关闭它,因为由于DataReader的性质,您将不再拥有数据。解决此问题的一种方法是在ExecuteReader方法中包含一个参数,如下所示:
cmd.ExecuteReader(CommandBehavior.CloseConnection)
然后,当您的阅读器关闭时,连接将关闭。
使用封装代码返回的datareader存在一个根本问题,因为连接必须通过所有这些打开,使得错误处理变得棘手。请考虑使用数据表( A ),这对于小型数据集几乎同样有效。通过这种方式,您可以立即关闭GetPost方法中的连接,而不用担心它,只需非常简单的错误处理。或者( B )将连接传递给GetPost,因此连接的所有Using / Dispose语法和错误处理都在一个地方显式。我建议选择A。
答案 4 :(得分:0)
为什么要让网页了解数据库呢?为什么不抽象出数据库知识,只返回包含数据库数据的列表或对象?只是看起来很多责任混合在一起,你可以让自己更轻松。
答案 5 :(得分:0)
这是一个非常简单的架构。正如CSharpAtl所建议的那样,你可以让它更复杂。但是,这似乎对你有用。
我要做的一个重要补充是使用try-finally块。将Close放在finally中将确保即使在处理过程中发生异常也会释放连接。
SqlDataReader reader;
try
{
///call our GetPost method
reader = DB.GetPost();
//output the result
reader.Read();
this.viewpost.InnerHtml = "<span id='post1_CreatedDate'>" + reader["CreatedDate"].ToString() + "</span><br>";
this.viewpost.InnerHtml += "<span class='blogheads'>" + reader["BlogTitle"].ToString() + "</span><p><p>";
this.viewpost.InnerHtml += reader["BlogText"].ToString();
}
finally
{
reader.Close();
}
答案 6 :(得分:0)
感谢所有好的提示,我决定在这里稍微不同但相关的主题继续这个主题: Asp.Net: Returning a DataSet from a Class
此致 熔体
答案 7 :(得分:0)
This article可能是您阅读的好资源。它显示了创建n层应用程序的基础知识。您可以创建数据访问组件,实体对象,业务层和表示层。他还使用像你所问的sql数据读取器,并且他展示了一种使用对象构建辅助方法的好方法。
如果您不喜欢阅读文章,那么他对同一主题也有一个pretty good video和code example您可以下载并查看这种创建数据驱动应用程序的方法的不同变体。
祝你好运,希望这有助于一些人。