在一个方法中构建多个查询的最佳方法c#asp.net

时间:2017-03-07 13:42:12

标签: c# sql asp.net sql-server datareader

我有一个页面加载方法,它将带有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,我的应用程序现在正常工作,但我觉得这是一个补丁来涵盖可能很糟糕的代码。

这样做的最佳做法是什么?非常感谢提前!

4 个答案:

答案 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,但代码更清晰。

相关问题