在一种方法中构建多个查询的最佳方式 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。
这为您封装了很多很好的实践……包括关闭连接。
您仍然需要关闭数据读取器,但代码更清晰了。
我有一个页面加载方法,它使用 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。 这为您封装了很多很好的实践……包括关闭连接。 您仍然需要关闭数据读取器,但代码更清晰了。