Calling Stored procedure with output - c#

I have been trying to retrieve some information from my database, and also retrieve the return value. I know the Stored Procedure works fine.
The code I use is a modified piece I use for registering the user. It's going wrong at the cmd.ExecuteReader part of my code.
protected void btn_login_Click(object sender, ImageClickEventArgs e)
{
//Actions after Submit button is clicked
Page.Validate(((ImageButton)sender).ValidationGroup);
if (Page.IsValid)
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["DbConnectString"].ConnectionString))
{
SqlCommand cmd = new SqlCommand("usp_validateUsers", conn);
//Input Values
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("username", Uname.Text);
cmd.Parameters.AddWithValue("password", pwd.Text);
//Return Values
SqlParameter retParam = cmd.Parameters.Add("#RetVal", SqlDbType.Int);
retParam.Direction = ParameterDirection.ReturnValue;
SqlParameter acsParam = cmd.Parameters.Add("#ac_status", SqlDbType.Int);
acsParam.Direction = ParameterDirection.Output;
SqlParameter nikParam = cmd.Parameters.Add("#memb_name", SqlDbType.VarChar);
nikParam.Direction = ParameterDirection.Output;
try
{
// Open Connection and execute Stored Proc
conn.Open();
///////////SOMETHING GOES WRONG HERE///////////////
cmd.ExecuteReader();
//Retrieve Data
int retVal = (int)retParam.Value;
string nickname = nikParam.Value.ToString();
string ac_stats = acsParam.Value.ToString();
if (retVal != 0)
{
//Invalid Username or password
}
else
{
//Login User
}
}
catch (Exception Error)
{
lbl_login.Text = "An error occured, please try again later";
debug.Text = Error.Message;
}
finally
{
debug.Text = "\n Clossing Connection";
if (conn.State == System.Data.ConnectionState.Open)
{
conn.Close();
}
}
}
}
}
When I just want to receive the return value I simply use cmd.ExecuteScalar(); I know how to receive data when I'm passing the SQL query to the SQL database, but it seems to be different when using Stored Procedures..
EDIT
Probably could improve this code further but it really does what it should do.
ALTER PROCEDURE dbo.usp_validateUsers
#username varchar(10),
#password varchar(10),
#ac_status char(1) OUTPUT,
#memb_name varchar(15) OUTPUT
AS
IF EXISTS(SELECT * FROM MEMB_INFO WHERE (memb___id = #username))
BEGIN
SELECT #ac_status = ac_status, #memb_name = memb_name
FROM MEMB_INFO
WHERE (memb___id = #username) AND (memb__pwd = #password)
RETURN 0
END
ELSE
BEGIN
return 1
END
When I use break points to catch possible exceptions in Visual Studio, It gives me:
String[4]: The Size property has an invalid size of 0

The error you mentioned may be caused by the fact that you're not specifying the size of your VarChar parameters. Instead of having lines like this:
SqlParameter nikParam = cmd.Parameters.Add("#memb_name", SqlDbType.VarChar);
Try this:
SqlParameter nikParam = cmd.Parameters.Add("#memb_name", SqlDbType.VarChar, 15);

You need to create a SqlDataReader.
From Ins and Outs of using Stored Procedures in C#
The SqlDataReader class is used to
read a forward only stream of records
returned from the database. The
SqlDataReader object is not
instantiated directly through a
constructor (hence the lack of the New
key word) but rather through the
ExecuteReader method of the SqlCommand
object. Before calling the
ExecuteReader method the connection to
the database is established using the
Open method of the SqlConnection
object.
Try
SqlDataReader drLogins;
Conn.Open();
drLogins = cmd.ExecuteReader();

Your #ac_status is defined as integer in parameter. change it character or string.
SqlParameter acsParam = cmd.Parameters.Add("#ac_status", SqlDbType.Int);

Related

Stored procedure returns no rows with SqlDataAdapter

I'm new to using SqlDataAdpter and I'm trying to execute a stored procedure. The stored procedure executes successfully but no rows are returned. I've used SQL Server Profiler to monitor the call and it runs successfully (I can copy and execute the query from profiler without modifying it and get results).
I have the following:
public ActionResult Index()
{
SqlConnection conn = null;
DataSet results = null;
try
{
string connectionString = // ... my connection
conn = new SqlConnection(connectionString );
string query = #"usp_mySP";
conn.Open();
SqlDataAdapter sqlAdpt = new SqlDataAdapter(query, conn);
sqlAdpt.SelectCommand.CommandType = CommandType.StoredProcedure;
var dataDate = new SqlParameter { ParameterName = "#DataDate", Value = DateTime.Now };
var idList = new SqlParameter { ParameterName = "#IDList", Value = "1231,2324,0833" };
sqlAdpt.SelectCommand.Parameters.Add(dataDate);
sqlAdpt.SelectCommand.Parameters.Add(idList);
results = new DataSet();
sqlAdpt.Fill(results);
sqlAdpt.Dispose();
}
catch (SqlException e)
{
throw new Exception("Exception:" + e.Message);
}
finally
{
if (conn != null)
conn.Close();
}
return View(results);
}
When I inspect the DataSet through the debugger, it always returns 0 rows.
Please help with what I'm doing wrong?
Note: I've also tried (but do NOT prefer) executing as a SQL command:
EXEC usp_mySP #DataDate, #IDList
and it didn't work either as I got int to varchar conversion errors.
I think you try to add SqlParameter using SqlCommand like this :
SqlCommand cmd = new SqlCommand();
cmd.parameter.addwithvalue(#DataDate,DateTime.Now);
So the reason was because of set nocount on. I added it to my sp and it works. Thank you everyone for clarifying.

C# is returning exception: Procedure has no parameters and arguments were supplied

I apologise for this formatting. I am new to programming and new to this site, so I will try and make the question as clear as possible.
I have a webform for accessing/modifying a Customer database. I have a button for entering new customers details which will automatically assign an ID number by getting the highest ID number from the database, and incrementing by one (and posting to form textbox).
This is the code I have written:
protected void btnNew_Click(object sender, EventArgs e)
{
Clear();
command.Connection = conn;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "NewCustomer";
conn.Open();
SqlParameter maxid = new SqlParameter();
maxid.ParameterName = "#MaxID";
maxid.SqlDbType = SqlDbType.Int;
maxid.Direction = ParameterDirection.Output;
command.Parameters.Add(maxid);
command.ExecuteNonQuery();
NewCustId = Convert.ToInt32(maxid.Value);
NewCustId += 1;
txtCustID.Text = (NewCustId).ToString();
txtCustID.DataBind();
conn.Close();
}
This is the stored procedure:
CREATE PROCEDURE NewCustomer
(#MaxID INT OUTPUT)
AS
BEGIN
SELECT #MaxID = MAX(CustID)
FROM dbo.Customer
END
I have tried many different ways of coding it, but nothing seems to work.
The code I have posted has an exception at ExecuteNonQuery saying arguments were supplied and procedure has no parameters. When I place command.Parameters.Add(maxid); underneath ExecuteNonQuery, it returns a 1.
I ran the SQL Query alone to see what would happen and it returns a correct answer in an unnamed cell. For some reason the Column Name disappears when it comes up. Then when I try to use the C# code to access the unnamed cell, I can't seem to access it because the column 'CustID' "doesn't exist".
With this code, I know that the SQL command is executing, and then the C# code increments by 1, but it seems that the return value I am getting is 0.
I appreciated any ideas that I can get on how to fix this. Thank you.
Edit: I have also tried:
DataTable table = new DataTable();
adapter.Fill(table);
NewCustId = table.Rows[0].Field("CustID");
(This is where it said 'CustID' column didn't exist)
Change your code to the following and try again:
Clear();
command.Connection = conn;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "NewCustomer";
conn.Open();
NewCustId = Convert.ToInt32(cmd.ExecuteScalar().ToString());
NewCustId += 1;
txtCustID.Text = NewCustId.ToString();
conn.Close();
And your stored procedure is:
CREATE PROCEDURE NewCustomer
(
)
AS
BEGIN
SELECT MAX(CustID)
FROM dbo.Customer;
END
ExecuteNonQuery() expects no results. Try ExecuteReader() instead.
I second what marc_S is saying about this running into issues.
Since you are using max ID and incrementing by 1 to insert a new record in the database, I suggest that you use Identity(seed, increment_value) for this column.
That way you don't have to find max to insert a new record and you avoid lots of transaction issues.
Once the transaction is done
Possible Design:
Create Table Customer
(
Id Int Identity(1,1),
Name varchar(50)
)
Create Proc NewCustomer
(
#Name varchar(50)
)
As
(
DECLARE #custID Int
SET NOCOUNT ON
INSERT INTO Customer (Name) Values('Your Name')
SET #custID = SCOPE_IDENTITY()
RETURN #custID
)
protected void btnNew_Click(object sender, EventArgs e)
{
Clear();
command.Connection = conn;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "NewCustomer";
conn.Open();
SqlParameter name = new SqlParameter();
name.ParameterName = "#Name";
name.Direction = ParameterDirection.Input;
name.SqlDbType = SqlDbType.Varchar;
name.Value = "Your Name";
command.Parameters.Add(name);
SqlParameter returnValue= new SqlParameter();
returnValue.ParameterName = "#custID";
returnValue.SqlDbType = SqlDbType.Int;
returnValue.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(maxid);
command.ExecuteNonQuery();
NewCustId = Convert.ToInt32(returnValue.Value);
txtCustID.Text = (NewCustId).ToString();
txtCustID.DataBind();
conn.Close();
}

'Procedure or function 'StoredProc' expects parameter '#variableInQuestion', which was not supplied' on variable formatted with a substring

I have the following stored proc that is throwing the aforementioned exception when I call it in a winform. The purpose of this form is to generate a number of randomized codes, format them, and store them in a database:
ALTER procedure [dbo].[StoredProc] (
#unimporantParam1 int,
#unimporantParam2 varchar(14),
#variableInQuestion varchar(10) OUT
)
As
Begin
exec dbo.GenerateRandomString 1,1,0,null,10,#variableInQuestion OUT
INSERT INTO [dbo].[sproc_table]
([unimportant_column1]
,[column_in_question]
,[unimportant_column2]
,[unimportant_column3]
,[unimportant_comlumn4])
SELECT #unimportantParam1
,(SELECT SUBSTRING(#variableInQuestion, 1, 3) + '-'
+ SUBSTRING(#variableInQuestion, 4, 4) + '-'
+ SUBSTRING(#variableInQuestion, 8, 3))
,GETDATE()
,0
,#unimportantVariable2
END
Being called by this C#:
private void btnGenerate_Click(object sender, EventArgs e)
{
int i;
var numberOfCodes = int.Parse(txtCodes.Text);
for (i = 1; i <= numberOfCodes; i++)
{
var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["Conn"].ConnectionString);
conn.Open();
try
{
var command = new SqlCommand("StoredProc", conn)
{
CommandType = CommandType.StoredProcedure
};
command.Parameters.Add(new SqlParameter("#unimportantParam1", SqlDbType.Int, 0, "param1"));
command.Parameters.Add(new SqlParameter("#unimportantParam2", SqlDbType.VarChar, 14, "param2"));
command.Parameters[0].Value = txtUnimportant1.Text;
command.Parameters[1].Value = txtUnimportant2.Text;
command.ExecuteNonQuery();
}
finally
{
conn.Close();
conn.Dispose();
}
}
}
When I test it in SQL Server, it does what its supposed to, but when I test through the C# code, I get the above error. Can anyone tell me what I'm doing wrong with the substring formatting or if its something else causing the error. I appreciate any help that can be given.
When you create the variableInQuestion in your winForm you have to set it as a parameter without seeing your c# code I am assuming you have not done this, to do this the code looks like the following:
SqlParameter param = new SqlParameter();
SqlCommand cmd = new sqlCommand();
param = cmd.Parameters.Add("#variableInQuestion", SqlDbType.VarChar);
param.Direction = ParameterDirection.ReturnValue;
after when you execute your stored procedure it will store the returned value in the command
and you can access it using:
String someString = cmd.Parameters["#variableInQuestion"].Value.ToString();

Can't get it! SqlParameter with ParameterName is not contained by this SqlParameterCollection. Stored proc param

I know that this question has been asked many times, And I have read many many answers, yet I can't figure out what is wrong. It's been hours. Any help would be soo appreciated. I am just trying to call a stored procedure in an ASP page, and I am unable to add the parameter properly, getting the exception that it is not in the collection.
I have modified my proc as follows to try to make it simple and isolate the issue.
ALTER PROCEDURE [dbo].[up_validateUserWithClinicCount]
#HTID INT = 0,
#ValidUserID INT OUTPUT,
#MultiClinicFlag INT OUTPUT
AS
DECLARE #vClinicCount INT = null
DECLARE #vUserValid INT = null
BEGIN
SET #ValidUserID = 2
SET #MultiClinicFlag = 1
END;
AND the C# code
String connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["PC3PaymentConnection"].ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand cmd = new SqlCommand("up_validateUserWithClinicCount", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#HTID", htId);
SqlParameter uidOut = new SqlParameter("#ValidUserID", SqlDbType.Int);
uidOut.Size = 4;
uidOut.Direction = ParameterDirection.Output;
cmd.Parameters.Add(uidOut);
SqlParameter pMultiClinics = new SqlParameter();
pMultiClinics.ParameterName = "#MultiClinicFlag";
pMultiClinics.SqlDbType = SqlDbType.Int;
pMultiClinics.Direction = ParameterDirection.Output;
cmd.Parameters.Add(pMultiClinics);
try
{
cmd.ExecuteNonQuery();
//--> Error points to the next line, and I have tried to use int.parse rather than convert also, with the same error -- parameter not in collection
MultiClinics = Convert.ToInt16(cmd.Parameters["pMultiClinics"].Value);
PC3User = Convert.ToInt16(uidOut.Value.ToString());
}
catch (SqlException sqlEx)
{
LbMsg.ForeColor = System.Drawing.Color.Red;
LbMsg.Text = sqlEx.Message;
}
}
}
Thanks if you can see what I am missing.
You have an object reference for the parameter already, you don't need to grab it from the parameters collection. Also, sql ints are 32-bit.
MultiClinics = (int)pMultiClinics.Value;
To retrieve from the parameter collection, use the ParameterName you gave it:
MultiClinics = (int)cmd.Parameters["#MultiClinicFlag"].Value;

Execute a pl/sql function with OracleCommand

i have this pl/sql function, the only thing it does is validate that the user exist in the database, if the user exists this returns "Y" but if the user dont exist this return "N", what I want is get the value that I return in pl/sql in c #.
I am using oracle 10g
CREATE OR REPLACE FUNCTION KRIST.f_Login (userName IN VARCHAR2,
password IN VARCHAR2)
RETURN VARCHAR2
IS
CURSOR USERFINDER IS
SELECT IdEmpleado
FROM EMPLEADO
WHERE Usuario=userName
AND Clave=password;
id number;
returnVal VARCHAR2(1);
BEGIN
OPEN USERFINDER;
FETCH USERFINDER INTO id;
IF(id IS NULL) THEN
returnVal:='Y';
RETURN returnVal;
END IF;
returnVal:='N';
RETURN returnVal;
CLOSE USERFINDER;
END;
/
how I can perform this function and get the result in a variable... i have thos code but dont works
OracleCommand cmd = new OracleCommand("krist.p_login",conn);
cmd.CommandType = CommandType.StoredProcedure; // use StoredProcedure with Functions as well
OracleParameter returnVal = new OracleParameter("returnVal",null);
OracleParameter p_one = new OracleParameter("userName","kristian");
OracleParameter p_two = new OracleParameter("password", "kristian");
returnVal.OracleType = OracleType.VarChar;
returnVal.Size = 1;
p_one.OracleType = OracleType.VarChar;
p_two.OracleType = OracleType.VarChar;
p_one.DbType = DbType.String;
p_two.DbType = DbType.String;
returnVal.DbType = DbType.String;
returnVal.Direction = ParameterDirection.ReturnValue;
p_one.Direction = ParameterDirection.Input;
p_two.Direction = ParameterDirection.Input;
cmd.Parameters.Add(p_one);
cmd.Parameters.Add(p_two);
cmd.Parameters.Add(returnVal);
cmd.ExecuteNonQuery();
String bval = Convert.ToString(returnVal.Value);
return bval;
The following code works for me.
NB: Your pl/sql code called the function KRIST.f_Login, but your c# called it krist.p_login
NB2: Your pl/sql code used Varchar2, but your c# used varchar
NB3: I am using Oracle.DataAccess.dll
NB4: I assume your return value buffer size could be 1, but try different sizes.
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
int RETURN_VALUE_BUFFER_SIZE = 32767;
OracleCommand cmd = new OracleCommand();
try {
cmd.Connection = conn;
cmd.CommandText = "KRIST.f_Login";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("returnVal", OracleDbType.Varchar2, RETURN_VALUE_BUFFER_SIZE);
cmd.Parameters["returnVal"].Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add("userName", OracleDbType.Varchar2);
cmd.Parameters["userName"].Value = "kristian";
cmd.Parameters.Add("password", OracleDbType.Varchar2);
cmd.Parameters["password"].Value = "kristian";
cmd.ExecuteNonQuery();
string bval = cmd.Parameters["returnVal"].Value.ToString();
return bval;
} catch (Exception e) {
// deal with exception
} finally {
command.Dispose();
connection.Close();
connection.Dispose();
}
As far as I remember If you are using ODP.NET you need to provide retVal parameter as first.
Something is wrong with ODP.NET and it dosn't bind parameters with provided parameter names but with order of parameters.
So simply change order to:
cmd.Parameters.Add(returnVal);
cmd.Parameters.Add(p_one);
cmd.Parameters.Add(p_two);
And in my sources I found that return parameter i called "RETURN" (not sure if it counts):
OracleParameter returnVal = new OracleParameter("RETURN",null);
A ha and one more thing. It will never reach last line - cuase return would terminate execute. Close it as soon as you don't need it anymore.
RETURN returnVal;
CLOSE USERFINDER; --<<-- won't close this cursor
ODP.net binds by order by default. This behavior can be modified with:
cmd.BindByName = true

Categories