Merci à quelques conseils et callbacks ici , j'ai changé mon code de ce désordre kludgy:
try { DataSet dsUsage = new DataSet(); SqlConnection conn = new SqlConnection("SERVER=PROSQL05;DATABASE=platypusdata;UID=duckbill;PWD=poisonToe42;Connection Timeout=0"); SqlDataAdapter da = new SqlDataAdapter(); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = Ssortingng.Format("Exec sp_ViewProductUsage_MappingRS '{0}', '{1}', '{2}'", mammal, dateBegin, dateEnd); da.SelectCommand = cmd; conn.Open(); da.Fill(dsUsage); conn.Close(); DataTable dtUsage = dsUsage.Tables[0]; if (dtUsage.Rows.Count > 0) { foreach (DataRow productUsageByMonthDataRow in dtUsage.Rows) { . . .
…pour ça:
try { SqlDataAdapter da = new SqlDataAdapter(); DataSet dsUsage = new DataSet(); using (SqlConnection conn = new SqlConnection(UsageRptConstsAndUtils.PlatypusConnStr)) { using (SqlCommand cmd = new SqlCommand("sp_ViewProductUsage_MappingRS", conn)) { cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@Unit", SqlDbType.VarChar).Value = _unit; cmd.Parameters.Add("@BegDate", SqlDbType.DateTime).Value = dtBegin; cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = dtEnd; da.SelectCommand = cmd; conn.Open(); //cmd.ExecuteReader(); <- Is this even necessary? da.Fill(dsUsage); } } DataTable dtUsage = dsUsage.Tables[0]; if (dtUsage.Rows.Count > 0) { // Populate the cells foreach (DataRow productUsageByMonthDataRow in dtUsage.Rows) { . . .
Notez que j'ai ExecuteReader
SqlCommand
ExecuteReader
commentaire dans le nouveau code parce qu'il semble inutile en raison du SqlDataAdapter
fourni le SqlCommand
. Ça fonctionne bien. Donc: ai-je raison de supposer que je peux supprimer cmd.ExecuteReader()
tout à fait? Y a-t-il un avantage à le conserver, ou est-ce que cela serait totalement redondant et créerait un «travail occupé» pour le process?
Donc, pour passer un tableau de SqlParameter (à la méthode ExecuteDataSet dans la réponse de MethodMan), je suppose que je dois d'abord faire quelque chose comme:
SqlParameter sqlp = new SqlParameter(); sqlp.ParameterName = "Unit"; sqlp.Value = _unit; cmd.Parameters.Add(sqlp);
…etc. (et puis les append à un tableau – ou, mieux, une list générique de SqlParameter).
Je viens juste de le faire pour la première fois: si vous utilisez l'exemple de MethodMan (ce que je fais) et que vous utilisez une requête sans paramètre, vous devez contourner la boucle d'ajout de paramètre comme ceci:
if (null != parameters) { foreach (var item in parameters) { cmd.Parameters.Add(item); } }
Je créerais personnellement une class SqlDBHelper et passerais appeler la procédure stockée en utilisant une méthode comme celle-ci
public static class SqlDBHelper { public static DataSet ExecuteDataSet(ssortingng sql, CommandType cmdType, params SqlParameter[] parameters) { using (DataSet ds = new DataSet()) using (SqlConnection connStr = new SqlConnection(ConfigurationManager.ConnectionSsortingngs["DbConn"].ConnectionSsortingng)) using (SqlCommand cmd = new SqlCommand(sql, connStr)) { cmd.CommandType = cmdType; foreach (var item in parameters) { cmd.Parameters.Add(item); } try { cmd.Connection.Open(); new SqlDataAdapter(cmd).Fill(ds); } catch (SqlException ex) { //log to a file or write to Console for example Console.WriteLine(ex.Message); } return ds; } } }
Si vous souhaitez renvoyer un DataTable, modifiez le type de return dans la signature de méthode et appelez le suivant dans l'instruction de return ci-dessous
public static DataTable ExecuteDataSet(ssortingng sql, CommandType cmdType, params SqlParameter[] parameters) return ds.Tables[0];
Voici un exemple sur comment vous appelleriez la méthode
someDataTable = SqlDBHelper.ExecuteDataSet("sp_ViewProductUsage_MappingRS", CommandType.StoredProcedure, new SqlParameter() { ParameterName = "@Unit", SqlDbType = SqlDbType.VarChar, Value = _unit }, new SqlParameter() { ParameterName = "@BegDate", SqlDbType = SqlDbType.DateTime, Value = dtBegin }, new SqlParameter() { ParameterName = "@EndDate", SqlDbType = SqlDbType.DateTime, Value = dtEnd } );