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

Best way to structure multiple queries in one method c# asp.net

我有一个页面加载方法,它使用 sql 查询加载 asp 下拉菜单到我的 SQL Server 2012 数据库。我是新手,基本上独立学习了很多我正在从事的合作项目需要完成的工作。

我一直 运行 遇到连接未正确关闭以及我的连接池爆炸的问题,我的应用程序只适度使用,所以我一直在努力改进我的执行方式在我的 c# 代码后面查询。但是我对自己对此的理解没有信心,所以我要 post 我的代码示例,希望更流利的人能够指导我一点。

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的query

我最近的错误是

已经有一个与此命令关联的打开的 DataReader,必须先将其关闭。

这促使我提出这个问题,我在我的 Web.config 连接字符串中设置了 MultipleActiveResultSets=true,我的应用程序现在可以工作了,但我觉得好像这是一个补丁来覆盖可能糟糕的代码。

执行此操作的最佳做​​法是什么?非常感谢!

这两个应该是不同的方法。一个获取类别,一个获取子类别。然后每个人都会有不同的连接,你不会有这个问题。

好吧,可能有多种方法,但我觉得您应该将所有这些查询包装在一个存储过程中,然后在您的代码后面调用该 SP。而不是使用 DataReader 使用 DataSet 并用不同的结果集填充它。

您还可以使用 DataReader 实例的 NextResult() 方法来获取下一个 SELECT 结果并进行处理。

您应该在 DataReader 上调用 Dispose 或将其放入 using 语句中,以便为您调用 Dispose()。

典型的 IDataReader 模式如下所示:

using (IDataReader r = query.ExecuteReader())
{
  while (r.Read())
  {
     // etc.
  }
}

当您不在 IDataReader 上调用 Dispose() 时,他无法被清理。而且我希望即使您在连接上调用 Dispose() 也无法清除您的连接,因为它仍然被您的 IDataReader 使用。

是的,每个连接您只能使用一个 IDataReader。 因此,正如其他人所写,您应该将其拆分为多个方法,并为每个方法使用一个连接。

顺便说一句: 最好不要使用"SELECT *"。只需查询您需要的字段即可。

对于您的直接问题,您在每个连接中使用了两个 cmd。 您最好使用单程、一个命令和多个结果。

这将允许您正确地关闭()您的数据读取器和您的连接...."returning them back to the pool"

由于您使用的是 SqlServer,它支持一个结果集 "trip"。

SELECT * FROM dbo.Category;SELECT * FROM dbo.SubCategory

将其用作您的 select 声明。

使用 .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" 对象,并且 return 那些到表示层。

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
}

然后让您的表示层 "bind" 到 ICollection of Categories。

您可能在表示层和数据层之间有一个业务层,但至少在表示层和数据层之间。

我还在下面的 link 中回答了一个问题...这与您的问题类似。他们的对象是 "Question" 和 "Answer",其中一个问题有 0:N 个答案。

在下面的问题中找到我的答案。

Return objects with populated list properties from stored procedure

请注意,您可以只在字符串中使用 2 select 查询(my/this 答案的第二行),也就是说,您不必创建存储过程。

另一种选择是使用 nuget 来获取 Microsoft.EnterpriseLibrary.Data。 这为您封装了很多很好的实践……包括关闭连接。 您仍然需要关闭数据读取器,但代码更清晰了。