Meilleure façon de structurer plusieurs requêtes dans une méthode c # asp.net

J'ai une méthode de chargement de page qui charge des lists déroulantes asp avec des requêtes SQL dans ma database SQL Server 2012. Je suis nouveau à cela et fondamentalement indépendamment appris beaucoup de choses à faire pour le projet de coopération sur lequel je travaille.

J'ai eu des problèmes avec les connections n'étant pas fermées correctement et avoir ma piscine de connection exploser avec une utilisation modérée de mon application, donc j'ai essayé d'améliorer la façon dont j'exécute mes requêtes dans mon code c # derrière. Mais je ne suis pas confiant dans ma compréhension de cela, donc je vais postr un exemple de mon code et j'espère que quelqu'un de beaucoup plus à l'aise pourrait être capable de me guider un peu.

ssortingng constr = ConfigurationManager.ConnectionSsortingngs["CurrencyDb"].ConnectionSsortingng; 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); } } } 

Ce qui précède est deux requêtes d'environ 8 sur ma méthode de chargement de la page.

Ma dernière erreur était

Il y a déjà un DataReader ouvert associé à cette command qui doit être fermé en premier.

Cela m'a incité à poser la question, j'ai mis MultipleActiveResultSets = true dans ma string de connection Web.config et mon application fonctionne maintenant, mais j'ai l'printing que c'est un patch pour couvrir ce qui est probablement du code merdique.

Quelle est la meilleure pratique pour ce faire? Merci beaucoup d'avance!

Pour votre question immédiate, vous utilisez deux cmds par connection. Vous pourriez être mieux en utilisant un voyage, une command, avec un résultat multiple.

Cela vous permettra de correctement .Close () votre lecteur de données et votre connection …. "les renvoyer à la piscine"

Puisque vous utilisez SqlServer, il supporte plusieurs jeux de résultats en un "sortingp".

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

Utilisez cela comme votre instruction select.

Utilisez une méthode .ExecuteReader ().

Et utilisez un .NextResult () pour passer d'un résultat (catégorie) au suivant (sous-catégorie)

Vous pouvez voir un exemple plus complet ici:

https://msdn.microsoft.com/en-us/library/system.data.idatareader.nextresult(v=vs.110).aspx

Ou même avec Entity Framework ici:

https://msdn.microsoft.com/fr-fr/library/jj691402%28v=vs.113%29.aspx?f=255&MSPPError=-2147217396

Maintenant, quelques trucs supplémentaires.

Vous mélangez votre couche de données et votre couche de présentation.

Vous devriez avoir votre datalayer remplir "Dto" parfois appelé "Poco" objects, et les returnner à la couche Présentation.

 public class Category public ssortingng CategoryKey{get;set;} public ssortingng CategoryName{get;set;} public ICollection<SubCategory> SubCategories {get;set;} 

..

  public class SubCategory public ssortingng SubCategoryKey{get;set;} public ssortingng 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 } 

Ensuite, ayez votre couche de présentation "bind" à l'ICollection des catégories.

Vous pourriez avoir une couche de gestion entre la présentation et les lecteurs de données, mais au less pour la présentation et les lecteurs de données.

J'ai également répondu à une question sur le lien ci-dessous … qui est similaire à la vôtre. Leurs objects sont "Question" et "Réponse" lorsqu'une Question a un Nombre de Réponses de 0: N.

Trouvez ma réponse à la question ci-dessous.

Renvoyer des objects avec des propriétés de list remplies à partir d'une procédure stockée

Remarque, vous pouvez simplement utiliser les 2 requêtes select dans une string (la deuxième ligne de ma / cette réponse), aka, vous n'avez pas besoin de créer une procédure stockée.

Une autre option consiste à utiliser nuget pour get Microsoft.EnterpriseLibrary.Data. Cela encapsule beaucoup de bonnes pratiques pour vous … y compris la fermeture des connections. Vous devrez toujours fermer votre lecteur de données, mais le code est beaucoup plus propre.

Eh bien, il pourrait y avoir plusieurs façons, mais je pense que vous devriez envelopper toutes ces requêtes dans une procédure stockée et appelez ce SP dans votre code derrière. Au lieu d'utiliser DataReader utilisez un DataSet et remplissez-le avec le jeu de résultats différent.

Vous pouvez également utiliser la méthode NextResult() de l'instance datareader pour get le résultat SELECT suivant et effectuer votre traitement.

Ces deux devraient être dans des methods différentes. Un pour get une catégorie et un pour get des sous-catégories. Ensuite, chacun aura une connection différente et vous n'aurez pas ce problème.

Vous devez appeler Dispose sur votre DataReader ou le placer dans une instruction using afin que Dispose () soit appelé pour vous.

Le model IDataReader typique ressemble à ceci:

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

Lorsque vous n'appelez pas Dispose () sur IDataReader, il ne peut pas être nettoyé. Et je m'attends à ce que votre connection ne puisse pas être nettoyée même lorsque vous appelez Dispose () sur la connection, car elle est toujours utilisée par votre IDataReader.

Et oui par connection, vous ne pouvez utiliser qu'un IDataReader. Donc, comme d'autres l'ont écrit, vous devriez le split en plusieurs methods et utiliser une connection par méthode.

Btw .: Il vaudrait mieux ne pas utiliser "SELECT *". Juste interroger les champs dont vous avez besoin.