我有一个页面加载方法,它将带有SQL查询的asp下拉列表加载到我的SQL Server 2012数据库中。我是新手,并且基本上独立地学习了我正在进行的合作项目需要做的很多工作。
我一直遇到连接未正确关闭的问题,并且我的连接池只是在适度使用我的应用程序时爆炸,所以我一直在努力改进我在c#代码后面执行查询的方式。但是我对这方面的理解并不自信,所以我将发布一个代码示例,并希望能够更流利的人能够指导我一点。
string constr = ConfigurationManager.ConnectionStrings["CurrencyDb"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr)) {
using (SqlCommand cmd = new SqlCommand("SELECT * FROM dbo.Category")) {
try {
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
con.Open();
//Populate Category Dropdown
DDCategory.DataSource = cmd.ExecuteReader();
DDCategory.DataTextField = "CategoryName";
DDCategory.DataValueField = "CategoryId";
DDCategory.DataBind();
}
catch (SqlException sqlex) {
throw new Exception("SQL Exception loading data from database. " + sqlex.Message);
}
catch (Exception ex) {
throw new Exception("Error loading Category data from database. " + ex.Message);
}
}
using (SqlCommand cmd = new SqlCommand("SELECT * FROM dbo.SubCategory ORDER BY SubCategoryName")) {
try {
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
//Populate SubCategory Dropdown
DDSubCategory.DataSource = cmd.ExecuteReader();
DDSubCategory.DataTextField = "SubCategoryName";
DDSubCategory.DataValueField = "SubCategoryId";
DDSubCategory.DataBind();
}
catch (SqlException sqlex) {
throw new Exception("SQL Exception loading data from database. " + sqlex.Message);
}
catch (Exception ex) {
throw new Exception("Error loading Subcategory data from database. " + ex.Message);
}
}
}
以上是关于我的页面加载方法的大约8的两个查询。
我的最新错误是
已经有一个与此命令关联的开放DataReader必须先关闭。
这促使我提出这个问题,我在我的Web.config连接字符串中设置了MultipleActiveResultSets = true,我的应用程序现在正常工作,但我觉得这是一个补丁来涵盖可能很糟糕的代码。
这样做的最佳做法是什么?非常感谢提前!
答案 0 :(得分:2)
好吧,可能有多种方式,但我觉得你应该将所有这些查询包装在一个存储过程中,然后在你的代码中调用该SP。而不是使用db.mycollection.aggregate([{
$project: {
byteLength: {$strLenBytes: "$name"}
}
}])
使用DataReader
并使用不同的结果集填充它。
您还可以使用DataSet
datareader实例方法获取下一个NextResult()
结果并进行处理。
答案 1 :(得分:1)
这两个应该采用不同的方法。一个获得类别,一个获得子类别。然后每个人都有不同的联系,你不会遇到这个问题。
答案 2 :(得分:1)
您应该在DataReader上调用Dispose,或者将其放在using语句中,以便为您调用Dispose()。
典型的IDataReader模式如下所示:
using (IDataReader r = query.ExecuteReader())
{
while (r.Read())
{
// etc.
}
}
当你没有在IDataReader上调用Dispose()时,他无法清理。而且我希望即使你在连接上调用Dispose()也无法清除你的连接,因为你的IDataReader会使用它。
对于每个Connection,您只能使用一个IDataReader。 因此,正如其他人写的那样,您应该将其拆分为多个方法,并为每个方法使用一个连接。
顺便说一下: 最好不要使用“SELECT *”。只需查询您需要的字段即可。
答案 3 :(得分:1)
对于您的直接问题,您每个连接使用两个cmd。 你可能最好使用一次性,一次命令,多次结果。
这将允许您正确。关闭()您的datareader和您的连接....“将它们返回池中”
由于您使用的是SqlServer,因此它在一个“行程”中支持多个结果集。
SELECT * FROM dbo.Category;SELECT * FROM dbo.SubCategory
将其用作选择语句。
使用.ExecuteReader()方法。
使用.NextResult()从一个结果(类别)移动到下一个(子类别)
您可以在此处查看更完整的示例:
https://msdn.microsoft.com/en-us/library/system.data.idatareader.nextresult(v=vs.110).aspx
甚至在这里使用Entity Framework:
https://msdn.microsoft.com/en-us/library/jj691402%28v=vs.113%29.aspx?f=255&MSPPError=-2147217396
现在有些额外的东西。
您正在混合数据层和表示层。
您应该让您的数据层填充“Dto”,有时称为“Poco”对象,并将它们返回到表示层。
public class Category
public string CategoryKey{get;set;}
public string CategoryName{get;set;}
public ICollection<SubCategory> SubCategories {get;set;}
..
public class SubCategory
public string SubCategoryKey{get;set;}
public string SubCategoryName{get;set;}
..
public class MyDataLayerObject
public ICollection<Category> GetAllCategories()
{
ICollection<Category> categories;
ICollection<SubCategory> subcats;
// write a datareader call here, and use it to populate multiple Category and SubCategory objects
// make sure you close the datareader when done
//now "match up" the subcats to its parent category
}
然后让您的表示层“绑定”到ICollection of Categories。
您可能在演示文稿和数据层之间有一个业务层,但至少对于演示文稿和数据层。
我也在下面的链接中回答了一个问题......这与你的相似。他们的对象是“问题”和“答案”,其中一个问题有0:N个答案。
在下面的问题中找到我的答案。
Return objects with populated list properties from stored procedure
注意,您可以在字符串中使用2个选择查询(我的/这个答案的第二行),也就是说,您不必创建存储过程。
另一种选择是使用nuget获取Microsoft.EnterpriseLibrary.Data。 这包含了很多很棒的实践......包括关闭连接。 您仍然需要关闭datareader,但代码更清晰。