Calling a stored procedure using C# - c#

private void btnGo_Click(object sender, EventArgs e)
{
Array IDlist = txtUserID.Text.Split(new char[] { });
ArrayList badID = new ArrayList();
foreach (string textLine in IDlist)
{
try
{
int LineID = Convert.ToInt32(textLine);
string emp = txtDistricts.Text;
command.Parameters.Add("#EmpID", SqlDbType.Int).Value = LineID;
if (!emp.Equals(string.Empty))
command.Parameters.Add("#SchoolDistricts", SqlDbType.NVarChar).Value = emp;
else command.Parameters.Add("#SchoolDistricts", SqlDbType.NVarChar).Value = DBNull.Value;
if (cbRemove.Checked)
command.Parameters.Add("#Options", SqlDbType.Int).Value = 1;
else if (cbReset.Checked)
command.Parameters.Add("#Options", SqlDbType.Int).Value = 0;
else command.Parameters.Add("#Options", SqlDbType.Int).Value = DBNull.Value;
SqlParameter returnValue = new SqlParameter("#return_value", DbType.String);
returnValue.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(returnValue);
conn.Open();
command.Connection = conn;
// command.ExecuteNonQuery();
command.ExecuteScalar();
String OutPutCheck = (command.Parameters["#return_value"].Value.ToString());
String getCheck = (command.ExecuteScalar().ToString());
OPBox.Text += LineID + "--->>" + OutPutCheck + "--->>" + getCheck + "\n";
conn.Close();
//flagUser(LineID, emp);
}
catch (Exception ex)
{
//stored procedure error
badID.Add(textLine);
conn.Close();
}
}}
I made an APP , which takes bunch of ID at a time. After btn_click these values put in array. Then from array each ID pass to store procedure one by one, and get return value. well First value give return value, but after that when second value pass to store procedure it gives following error.
> ERROR::::ex = {"Procedure or function
> usp_Flag_Employee has too many
> arguments specified."}

You keep adding parameters to your command object without reseting it. You should move your connection and command objects into the method where they are being called and use 'using' statements.
Because your connection and command are class fields, each instance of the loop is re-adding the parameters to the old set of parameters. At minimum, reset the parameters collection at the top of the loop.

You are passing too many parameters to the procedure. If you paste the procedure code we can help identify, however just do a count of the params and check to ensure you have all defined in the proc.

I don't see any code generating the SqlCommand object in your example.
If command is local to the class, there's a very good chance that it has already been used (which means it probably already has parameters added to it).
I also see no code that sets the command type to StoredProcedure. Depending on what the command text is, this could be the issue as well (if you're simply passing the stored procedure name without setting the type...it will see the command as having no parameters).
Re-Writing the code to use its own SqlConnection and SqlCommand would make this much easier to debug (unless, of course, it already is and you didn't give us that code).
EDIT
I just noticed that you're using the code inside a foreach loop without clearing the parameters. That is yet another issue (and probably the most likely cause for this issue). Just be sure to call command.Parameters.Clear() at the beginning of each loop before adding the new parameters.

Call the Clear method before adding the parameters.

It works the first time because your command object has no parameters. For each subsequent iteration you keep on adding another set of parameters to your command object.
You need to clear the parameters for your command object on each iteration.

Related

error executing procedure in the loop

I'm facing problem while executing procedure inside loop. My requirment is to insert data to table. first column is alphabet which I try to get in loop and next three are common for all rows. But I'm getting error after first iteration saying that variable must be unique.
string str = Properties.Settings.Default.con;
SqlConnection con = new SqlConnection(str);
char[] az = Enumerable.Range('A', 'Z' - 'A' + 1).Select(i => (Char)i).ToArray();
SqlCommand cmd = new SqlCommand("Execute InsertPurchase #ShipTo,#StoreName,#desc,#Alpha", con);
try
{
cmd.Parameters.AddWithValue("#ShipTo", txtstoreto.Text);
cmd.Parameters.AddWithValue("#StoreName", txtstorefrom.Text);
cmd.Parameters.AddWithValue("#desc", Globals.s_desc.ToString());
con.Open();
foreach (var c in az)
{
cmd.Parameters.AddWithValue("#Alpha", c.ToString());
cmd.ExecuteNonQuery();
}
con.Close();
j = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Error message:
The variable name '#Alpha' has already been declared. Variable names must be unique within a query batch or stored procedure.
You're adding parameter Alpha in the loop over and over again.
So instead of adding it in the loop you just have to set its value:
cmd.Parameters.Add("#Alpha", SqlDbType.VarChar);
con.Open();
foreach (var c in az)
{
cmd.Parameters["#Alpha"].Value = c.ToString();
cmd.ExecuteNonQuery();
}
Also notice that using of AddWithValue is not a good idea in most cases since it tries to deduce parameter type from the value passed. In most cases it is better to explicitly set parameter type.
I think you keep on adding the #Alpha parameter over and over...
First time add the parameter and set the value.
Every subsequent iteration, just set the value.
eg first iteration....
cmd.Parameters.AddWithValue("#Alpha", c.ToString());
Subsequent iterations....
cmd.Parameters["#Alpha"].Value = c.ToString();
Good luck.
As an alternative, you can move all parameter declarations in your for loop and Clear them in every iteration.
foreach (var c in az)
{
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#ShipTo", txtstoreto.Text);
cmd.Parameters.AddWithValue("#StoreName", txtstorefrom.Text);
cmd.Parameters.AddWithValue("#desc", Globals.s_desc.ToString());
cmd.Parameters.AddWithValue("#Alpha", c.ToString());
cmd.ExecuteNonQuery();
}
But of course, this adds unnecessary first 3 parameter in every iteration and clear them again.
By the way, don't use AddWithValue as much as you can. It may generate unexpected and surprising results sometimes. Use Add method overload to specify your parameter type and it's size.
Also use using statement to dispose your connection and command automatically instead of calling Close or Dispose methods manually.
You have to clear the variable to add again Something like this:
foreach (var c in az)
{
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#ShipTo", txtstoreto.Text);
cmd.Parameters.AddWithValue("#StoreName", txtstorefrom.Text);
cmd.Parameters.AddWithValue("#desc", Globals.s_desc.ToString());
cmd.Parameters.AddWithValue("#Alpha", c.ToString());
cmd.ExecuteNonQuery();
}

The variable name '#product_Id' has already been declared. Variable names must be unique within a query batch or stored procedure

i insert the data from datagridview to database table. but the error that come in the exception i write in the title. the value save in the database table as well.
private void btnSavePurchases_Click(object sender, EventArgs e)
{
if ((string.IsNullOrEmpty(txtPGrandTotal.Text)) || (txtPGrandTotal.Text == "0"))
{
MessageBox.Show("No record available");
}
else
{
try
{
string query1 = "INSERT INTO purchases (productId) values (#product_Id)";
command = DBConnectivity.getCommandForQuery(query1, connection);
for (int i = 0; i < dGvPurchases.Rows.Count; i++)
{
// command.Parameters.Clear();
command.Parameters.AddWithValue("product_Id", dGvPurchases.Rows[i].Cells[9].Value);
command.ExecuteNonQuery();
}
}
catch (Exception ex)
{
}
}
}
Probably
AddWithValue("product_Id"...
should be
AddWithValue("#product_Id"...
By the way, since you add your parameters in a for loop, you need clear them top of your for loop. That's why you need to uncomment your command.Parameters.Clear() part. Without Clear method, you try to add same parameter name over and over again to same command and you will get an error in your second iteration.
As an another solution, you can declare your parameter name outside of your loop and add it's value inside of loop.
And don't use AddWithValue as much as possible. It may generate unexpected results sometimes. Use .Add() overloads to specify your db type and it's size.
Don't forget to use using statement as well to dispose your command object.
I don't see command anywhere in the scope here. Probably it is a class variable. That is one part of your issue.
Move the construction of the command variable to inside your method:
var command = DBConnectivity.getCommandForQuery(...);
^^^
Second, your for look causes issues. You can't add the same parameter over and over again. If you want to insert multiple rows, add multiple insert statements. Create the command inside the for loop.
problem is that command.Parameters.AddWithValue adds the parameter to the list of parameters. you can't add a parameter twice. since you call the command several times, define the parameter outside and set value within the loop:
string query1 = "INSERT INTO purchases (productId) values (#product_Id)";
command = DBConnectivity.getCommandForQuery(query1, connection);
// Define the Parameter just once
var param = command.Parameters.Add("#product_Id", SqlDbType.Int);
for (int i = 0; i < dGvPurchases.Rows.Count; i++)
{ // set value while looping
param.Value = dGvPurchases.Rows[i].Cells[9].Value;
command.ExecuteNonQuery();
}

Set C# variable as a Select from database

How would I take info stored in a Select method and transfer it to a string? I'm trying to get the max value from the match_id column and get its value from command.CommandText into the matchCode string. Where would I go from here?
string connectString = "Server=myServer;Database=myDB;Uid=myUser;Pwd=myPass;";
string matchCode = "";
MySqlConnection connect = new MySqlConnection(connectString);
MySqlCommand command = connect.CreateCommand();
command.CommandText = "SELECT MAX(VAL(match_id)) FROM `data`";
try
{
connect.Open();
command.ExecuteNonQuery();
matchCode = "??";
connect.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
I'm new to C#, as it's like my fourth day trying it out. Thanks for the help!
The ExecuteNonQuery() method is for INSERT/UPDATE/DELETE queries. If you're just getting a single value back, use ExecuteScalar(). If you're getting a whole result set back, use ExecuteReader() or Fill() a DataSet object.
Also, there are some things that are idiomatic to C# that you should be doing:
public int GetMatchCode()
{
//this could be loaded from config file or other source
string connectString = "Server=myServer;Database=myDB;Uid=myUser;Pwd=myPass;";
string sql = "SELECT MAX(VAL(match_id)) FROM `data`";
using (var connect = new MySqlConnection(connectString))
using (var command = new MySqlCommand(sql, connect))
{
connect.Open();
var result = command.ExecuteScalar();
if (result == DBNull.Value)
{
//what you do here depends on your application
// if it's impossible for the query to return NULL, you can even skip this
}
return (int)result;
}
}
Some of the changes need explanation:
I don't ever call .Close(). The using block takes care of that for me, even if an exception was thrown. The old code would have left the connection hanging if an exception occured.
.Net developers tend to believe in very small methods. More than that, this method ought to be part of a class that has nothing but other simple public data access methods and maybe a few private helper methods or properties for abstracting common code in the class.
There is no exception handling code here. If you have small methods that are part of a generic database access class, exception handling should be at higher level, where you are better positioned to make decisions about how to proceed.

How to read the output variable from .net c#?

Does anyone know how can I read the output variable from .net c#?
Example:
If I have the following stored proc which will return the output variables (#customer_id, #customer_name, #customer_address, #customer_age) instead of the select variable, how can I read the output variable with the following?
mySqlCommand.CommandText = "EXEC app_customers #name=" + sName.Text;
mySqlConnection.Open();
SqlDataReader mySqlDataReader = mySqlCommand.ExecuteReader();
while (mySqlDataReader.Read())
{
}
When the result is a single value (or if you're just interested in the first value in the first column), use the method ExecuteScalar.
It returns an object, simply cast it to the expected type.
int id = (int)mySqlCommand.ExecuteScalar();
Note: the way you're invoking a procedure is not the normal way to do it. Set the command to reference the stored procedure, then add appropriate parameters to the command.Parameters collection. Invoking the procedure using "exec ..." is not a best practice and may even leave you vulnerable. If you need more info on executing such a call, start here.
Edit:
If it is truly an output parameter you need to capture (I believe I misread your question), then the above paragraph is even more applicable. Consider this approach:
mySqlCommand.CommandText = "app_customers";
mySqlCommand.CommandType = System.Data.CommandType.StoredProcedure;
mySqlCommand.Parameters.AddWithValue("#name", theValue);
var customerIdParam = mySqlCommand.Parameters.Add("#customer_id", System.Data.SqlDbType.Int);
customerIdParam.Direction = System.Data.ParameterDirection.Output;
// add more parameters, setting direction as appropriate
mySqlCommand.ExecuteNonQuery();
int customerId = (int)customerIdParam.Value;
// read additional outputs

Weird behavior with two output parameters in a stored proc called from c#

I've modified an existing strored procedure. It originally had one ouput parameter in the stored proc and it was set up as follows in the c# code that called it:
cmd.Parameters.Add("#Var1Param", SqlDbType.BigInt);
if (Var1 == 0)
cmd.Parameters["#Var1"].Value = DBNull.Value;
else
cmd.Parameters["#Var"].Value = Var1;
cmd.Parameters["#Var1"].Direction = ParameterDirection.InputOutput;
cmd.ExecuteNonQuery();
// Get Var1
Var1= dataMorph.ToInt64(cmd.Parameters["#Var1"].Value.ToString());
Just to clarify, this parameter was declared as OUTPUT in the stored proc but as inputoutput in the C# code. This worked fine.
I have added another parameter to the same stored procedure and I want to retrieve both from the C# code. The C# code now is as follows:
SqlParameter Var1Param;
if (VAR1 == 0)
Var1Param = new SqlParameter("#Var1", DBNull.Value);
else
Var1Param = new SqlParameter("#Var1",Var1) ;
Var1Param.Direction = ParameterDirection.InputOutput ;
cmd.Parameters.Add(Var1Param);
Again this parameter is declared as output in the stored proc but inputoutput in the c# code.
Here is the new parameter. This is declared as output in the stored procedured. Here is the C# code.
SqlParameter Var2Param = new SqlParameter("#Var2", 0);
Var2Param.Direction = ParameterDirection.Output;
cmd.Parameters.Add(Var2Param);
I only want to output the second parameter as you can see. The assignment of 0 to this parameter seems to be a standard practice despite the fact it's an output variable only. I'm not sure if need to give it a type.
Now the execution
// Execute
cmd.ExecuteScalar();
connection.Close();
// Get DonationID
Var1 = dataMorph.ToInt64(cmd.Parameters["#Var1"].Value.ToString());
//Get Supersession Daf ID return param to see if new DAF was created
Var2 = dataMorph.ToInt64(cmd.Parameters["#Var2"].Value.ToString());
What happens is that both the var1 and vaf2 parameters contain the value that was assigned to #Var2 parameter in the stored procedure. I have read that any number of parameters and parameter types can be used but it seems like the value assigned to #Var2 is overwriting the Value that had been passed in or assigned to Var1.
Any advice? I know I can work around this by having multiple result sets and putting my output values in the second result set but I'd rather not deal with Kludges unless I have to. I've seen a lot of posts about the odd state of parameters after they return from stored procs and are accessed in c#. Is this type of behavior a bug?
I will point out that I'm using executenonquery because the SP does an update. sarfeast is using execute scalar. I'm assuming that this shouldn't make any difference but I'll ask if anyone has any ideas on why this is happening. I modified the code by specifying sizes for the sqlparameters and now the value for var2 is showing up in var1 and var2 is Null!!!
Any advice would be appreciated.
The following code seems to work just fine so perhaps this has something to do with the logic in your stored procedure?
CREATE PROCEDURE Outs
#var1 INT OUTPUT,
#var2 INT OUTPUT
AS
BEGIN
SELECT #var1 = 1,
#var2 = 2
END
GO
var connectionstring = #"server=rickshaw;database=becak;Trusted_Connection=true;";
using(var conn = new SqlConnection(connectionstring))
using(var cmd = new SqlCommand("Outs", conn))
{
try
{
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
cmd.Parameters.Add("#var1", SqlDbType.BigInt);
cmd.Parameters.Add("#var2", 0);
cmd.Parameters["#var1"].Value = DBNull.Value;
cmd.Parameters["#var1"].Direction = ParameterDirection.InputOutput;
cmd.Parameters["#var2"].Value = 0;
cmd.Parameters["#var2"].Direction = ParameterDirection.Output;
cmd.ExecuteScalar();
conn.Close();
var var1 = cmd.Parameters["#var1"].Value;
var var2 = cmd.Parameters["#var2"].Value;
Console.WriteLine("var1=" + var1);
Console.WriteLine("var2=" + var2);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Console.ReadLine();

Categories

Resources