简体   繁体   中英

Using Stored Procedure to Insert parameters from DataTable

I am trying to insert data using a stored procedure that has two tables. This first table is data is through text boxes the second data is through a grid which I stored in the database and passed to be inserted. The problem is when reading datatable and inserting it says there are too many parameter which happens to add in the for loop. Any suggestion how to handle this as the SP? Thanks in advance.

CODE:

try
{
  SqlConnection conn = new SqlConnection();
  conn.ConnectionString = strConnection;
  SqlCommand cmd = new SqlCommand();
  cmd.Connection = conn;
  cmd.CommandTimeout = 120;
  cmd.CommandType = CommandType.StoredProcedure;
  cmd.CommandText = "insFamilyDetails";
  cmd.Parameters.AddWithValue("@strHusbandName", strHusbandName);
  cmd.Parameters.AddWithValue("@strRelation", strRelation);
  ....
  ....
   // Child Details
  for (int i = 0; i < strChildredDetails.Rows.Count; i++)
  {
    cmd.Parameters.AddWithValue("@strChildName", strChildredDetails.Rows[i][0].ToString());
    cmd.Parameters.AddWithValue("@strDOB", strChildredDetails.Rows[i][1]);
    cmd.Parameters.AddWithValue("@strBaptisedon", strChildredDetails.Rows[i][2]);
    cmd.Parameters.AddWithValue("@strFirstComOn", strChildredDetails.Rows[i][3]);
    cmd.Parameters.AddWithValue("@strConfirmedOn", strChildredDetails.Rows[i][4]);
    cmd.Parameters.AddWithValue("@strMarried", "0");
    cmd.Parameters.AddWithValue("@strAlive", "1");
  }
  conn.Open();
  ReturnValue = Convert.ToBoolean(cmd.ExecuteNonQuery());
  conn.Close();
}
catch (Exception e)
{
 DL_LogAppErrors(e.ToString(), System.Reflection.MethodBase.GetCurrentMethod().Name, "Insert Family Details");
 return ReturnValue;
}

return ReturnValue;

You are adding parameters in command in each iteration of the loop. After first iteration you are trying to add same parameter name in parameter collection. You probably need to clear the collection of parameter on each iteration using SqlParameterCollection.Clear . Clear the parameter collection after executing command (In loop body).

conn.Open();
for (int i = 0; i < strChildredDetails.Rows.Count; i++)
{
    cmd.Parameters.AddWithValue("@strChildName", strChildredDetails.Rows[i][0].ToString());
    cmd.Parameters.AddWithValue("@strDOB", strChildredDetails.Rows[i][2]);
    cmd.Parameters.AddWithValue("@strBaptisedon", strChildredDetails.Rows[i][2]);
    cmd.Parameters.AddWithValue("@strFirstComOn", strChildredDetails.Rows[i][3]);
    cmd.Parameters.AddWithValue("@strConfirmedOn", strChildredDetails.Rows[i][4]);
    cmd.Parameters.AddWithValue("@strMarried", "0");
    cmd.Parameters.AddWithValue("@strAlive", "1");
    ReturnValue = Convert.ToBoolean(cmd.ExecuteNonQuery());
    cmd.Parameters.Clear();
}
conn.Close();

If you have many records to insert in a table then you can send the comma separated values in SP and split then in SP and insert them. It will save db calls. This post will show how you can do that.

I assume from the code you're going to add into a main table, and Child table. For this case, you need to separate the process into two:

  1. Add the data for in main table
  2. Loop to add the child data
    Note: you need to clear the parameters before adding a new set, OR instead of adding new parameters, change the value of existing parameters

EDIT: Using Transaction

con.Open();
SqlTransaction trans = con.BeginTransaction();

try {
    // Execute the SP here
    // After all SP executed, call the commit method
    trans.Commit();
} catch (Exception ex) {
    // An error happened, rollback
    trans.RollBack();
}
con.Close();

For each row you want to insert you have to call the ExecuteNonQuery() function ie, it should be inside the for loop and after that clear the parameter collection at the end of loop.

  conn.Open();
// Child Details
  for (int i = 0; i < strChildredDetails.Rows.Count; i++)
  {
   cmd.Parameters.AddWithValue("@strHusbandName", strHusbandName);
   cmd.Parameters.AddWithValue("@strRelation", strRelation);
  ....
  ....
    cmd.Parameters.AddWithValue("@strChildName", strChildredDetails.Rows[i][0].ToString());
    cmd.Parameters.AddWithValue("@strDOB", strChildredDetails.Rows[i][1]);
    cmd.Parameters.AddWithValue("@strBaptisedon", strChildredDetails.Rows[i][2]);
    cmd.Parameters.AddWithValue("@strFirstComOn", strChildredDetails.Rows[i][3]);
    cmd.Parameters.AddWithValue("@strConfirmedOn", strChildredDetails.Rows[i][4]);
    cmd.Parameters.AddWithValue("@strMarried", "0");
    cmd.Parameters.AddWithValue("@strAlive", "1");
  ReturnValue = Convert.ToBoolean(cmd.ExecuteNonQuery());
cmd.Parameters.Clear();

}

As already said, you need to have ExecuteNonQuery inside for each loop, if you want to insert records of your grid.

Alternate option would be to Use Table Valued Paramter if you're using SQL Server 2008, that would make life more easy and you don't have to make round trip for each record of your gridview. Just pass the datatable.

Please check this link.

Edit:

For SQL Server 2005, you might want to use XML. Please check this link.

public string SerializeObject<T>(T Obj)
{
string strxml = string.Empty;
using (StringWriter sw = new StringWriter())
{
    XmlSerializer xs = new XmlSerializer(typeof(T));
    xs.Serialize(sw, Obj);
    strxml = sw.ToString();
}
return strxml;
}

Link contains above function, pass your datatable to this function, check out the generated XML and use same casing in stored procedure for elements in XML as XML is case sensitive.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM