I have a stored procedure that returns two recordsets which i call using GetReader. I iterate the first, call IDataReader.NextResult(), then iterate the second.
I assign values to output parameters in the sp, but when i check the values after finishing with my reader, my output parameters are null. Looks like a bug. I don't want to use a select since i don't like fudges. Some snippets...
...
sp.Command.AddParameter("#SelectedTabID", selectedTabID, DbType.Int32);
sp.Command.AddParameter("#CurrentTabID", 0, DbType.Int32, ParameterDirection.Output);
sp.Command.AddParameter("#TypeID", 0, DbType.Int32, ParameterDirection.Output);
(note doing it this way or using AddOutputParameter() yields same results)
...
using(IDataReader reader = sp.GetReader())
{
while (reader.Read()) {...}
if (reader.NextResult()) {while (reader.Read()) {...}}
}
...
int one = (int)sp.OutputValues[0]; //null expected an int
int two = (int)sp.OutputValues[1]; //null expected an int
Looking forward to some gems of wisdom :)
You need to close the reader first and then retrieve the output parameter. Output params return null when the reader is open.
More info can be found here
http://amilagm.com/2010/11/output-variable-values-not-returned-from-sql-server-sp-in-c-sharp/
Hope this helps.
The easiest way to get the output parameter is to use an instantiated variable. What I mean is keep a reference to your parameters, then once you execute your sproc, then you can inspect them like this:
SqlCommand cmd = new SqlCommand();
cmd.Connection = ConfigurationManager.ConnectionStrings["MyCon"].ToString();
cmd.CommandText = "MySproc";
SqlParameter parmOut = new SqlParameter("#StuffIWant", SqlDbType.Int);
parmOut.Direction=ParameterDirection.Output;
cmd.Parameters.Add(parmOut);
cmd.ExecuteNonQuery();
string theThingIWant = parmOut.Value.ToString();
This may not be using a datareader, but you may be able to use this to find the right answer.
Good Luck.
Slightly confused here...are you expecting output of scalar values or some kind of recordset? Get Reader would only really make sense if you have e.g. some cursor coming back as out parameter...
You may want to call "ExecuteNonQuery()" on your command and ensure that you set the CommandType correctly (CommandType.StoredProcedure)
This is subsonic failing, works fine as a bog standard SQLConnection/Command
The answer is that you have to close the reader before you can access the output parameters.
From: This Page
Make sure you retrieve the recordset first as an SqlDataReader
via cmd.ExecuteReader() Process
through all recordsets and then...
Make sure you CLOSE the recordset,
or SqlDataReader via reader.Close()
before trying to retrieve the output parameters
Related
I'm trying to return all rows of a single column in my database to populate a list. When I execute the stored procedure in SQL, it works fine, but nothing gets returned when I try to do it in C#.
public static List<string> GetRows(string filter_one, string filter_two)
{
var retrievedRows = new List<string>();
var storedProc = "dbo.MyStoredProc";
using (SqlConnection connection = new SqlConnection(MY_CONNECTION_STRING))
using (SqlCommand command = new SqlCommand(storedProc, connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#FilterOne", SqlDbType.VarChar).Value = filter_one;
command.Parameters.Add("#FilterTwo", SqlDbType.VarChar).Value = filter_two;
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
retrievedRows.Add(reader.GetString(0));
}
}
}
return retrievedRows;
}
Any ideas? I get no errors in the console or when I run it on IIS Express either. When I watch retrievedRows, the size stays at 0 even though when I run the same query in SQL with the same passed parameters, it returns results for me.
EDIT: Please excuse me, my brain must be running a bit slow today. One of the parameters I was passing was pointed at the (empty) value of the wrong webcontrol. I don't know how I missed this.
There is only one issue with your posted snippet that I can see, which could pose a problem:
command.Parameters.Add("#FilterOne", SqlDbType.VarChar).Value = filter_one;
command.Parameters.Add("#FilterTwo", SqlDbType.VarChar).Value = filter_two;
In this section, you're adding two VARCHAR parameters but not specifying a length for them. Try changing your code to add a length specification:
var filterOne = new SqlParameter("FilterOne", System.Data.SqlDbType.VarChar, 50);
The constructor in use here is SqlParameter(string, SqlDbType, int):
Parameters
-
parameterName (String): The name of the parameter to map.
dbType (SqlDbType): One of the SqlDbType values.
size (Int32): The length of the parameter.
When working with VARCHAR you must specify a length or anything outside of the default length (which is 1 byte for definitions and variables, and 30 bytes for CAST and CONVERT) will be truncated:
When n isn't specified in a data definition or variable declaration statement, the default length is 1. If n isn't specified when using the CAST and CONVERT functions, the default length is 30.
I have a stored procedure which checks the username and the password from a SQL Server database table. The stored procedure returns 1 if the username and the password is correct or returns 0. Here is the code. Could you please tell me how can I get the 1 or 0 pls? The rdr.toString does not work.
SqlCommand cmd = new SqlCommand("sp_IsValidLogon", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#Username", textBox1.Text));
cmd.Parameters.Add(new SqlParameter("#Password", textBox2.Text));
rdr = cmd.ExecuteReader();
label1.Text = rdr.ToString();
Try this
label1.Text=cmd.ExecuteScalar().ToString();
instead of this:
rdr = cmd.ExecuteReader();
label1.Text=rdr.ToString();
This should work fine:
if (rdr.Read())
label1.Text = rdr[0].ToString();
You first must call .Read() method once to "initialize" the data reader then take the value of the first field - assuming that's all your stored procedure returns, it will work.
You can do all of this without Reader though:
label1.Text = cmd.ExecuteScalar().ToString();
The ExecuteScalar() exists exactly for this purpose - read one single value from database.
If you are returning it from the sproc using the RETURN statement, then you need to add another INTEGER parameter to the SqlCommand in your .NET code with a ParameterDirection = ParameterDirection.ReturnValue.
Then after executing the sproc, just retrieve the value of that param from the SqlCommand.
Use ExecuteScalar insted. Example here:
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar.aspx
I assume that your stored procedure has an actual "return" statement that returns 0 or 1. in that case, add a sqlparameter to your command with ParameterDirection set to "ReturnValue".
ExecuteNonQuery should work fine in this case.
ExecuteScalar returns the value of the first column of the first row. If you are not "returning" the 0 or 1 from the stored procedure as a query result, then that is not what you want.
However, without seeing your stored procedure code I can't tell which of the two approaches is the one you need.
I am new to writing Stored Procedure. So I wrote one with output parameters and want to access the output value, hot to do it.
My Stored Procedure:
ALTER PROCEDURE selQuery
(
#id int, #code varchar(50) OUTPUT
)
AS
SELECT RecItemCode = #code, RecUsername from Receipt where RecTransaction = #id
RETURN #code
If trying to set "#code=RecItemCode" getting error as : "A SELECT statement that assigns a value to a variable must not be combined with Data Retrieval operations."
And I am using the Stored Procedure as:
con.Open();
cmd.Parameters.AddWithValue("#id", textBox1.Text);
SqlParameter code = new SqlParameter("#code", SqlDbType.Int);
code.Direction = ParameterDirection.Output;
cmd.Parameters.Add(code);
SqlDataReader sdr = cmd.ExecuteReader();
MessageBox.Show(cmd.Parameters["#code"].Value.ToString()); // getting error
con.Close();
Error : "Object reference not set to an instance of an object."
I want to get the value of output parameter. How to get that?
Thanks.
There are a several things you need to address to get it working
The name is wrong its not #ouput its #code
You need to set the parameter direction to Output.
Don't use AddWithValue since its not supposed to have a value just you Add.
Use ExecuteNonQuery if you're not returning rows
Try
SqlParameter output = new SqlParameter("#code", SqlDbType.Int);
output.Direction = ParameterDirection.Output;
cmd.Parameters.Add(output);
cmd.ExecuteNonQuery();
MessageBox.Show(output.Value.ToString());
The SQL in your SP is wrong. You probably want
Select #code = RecItemCode from Receipt where RecTransaction = #id
In your statement, you are not setting #code, you are trying to use it for the value of RecItemCode. This would explain your NullReferenceException when you try to use the output parameter, because a value is never assigned to it and you're getting a default null.
The other issue is that your SQL statement if rewritten as
Select #code = RecItemCode, RecUsername from Receipt where RecTransaction = #id
It is mixing variable assignment and data retrieval. This highlights a couple of points. If you need the data that is driving #code in addition to other parts of the data, forget the output parameter and just select the data.
Select RecItemCode, RecUsername from Receipt where RecTransaction = #id
If you just need the code, use the first SQL statement I showed you. On the offhand chance you actually need the output and the data, use two different statements
Select #code = RecItemCode from Receipt where RecTransaction = #id
Select RecItemCode, RecUsername from Receipt where RecTransaction = #id
This should assign your value to the output parameter as well as return two columns of data in a row. However, this strikes me as terribly redundant.
If you write your SP as I have shown at the very top, simply invoke cmd.ExecuteNonQuery(); and then read the output parameter value.
Another issue with your SP and code. In your SP, you have declared #code as varchar. In your code, you specify the parameter type as Int. Either change your SP or your code to make the types consistent.
Also note: If all you are doing is returning a single value, there's another way to do it that does not involve output parameters at all. You could write
Select RecItemCode from Receipt where RecTransaction = #id
And then use object obj = cmd.ExecuteScalar(); to get the result, no need for an output parameter in the SP or in your code.
You need to define the output parameter as an output parameter in the code with the ParameterDirection.Output enumeration. There are numerous examples of this out there, but here's one on MSDN.
SqlCommand yourCommand = new SqlCommand();
yourCommand.Connection = yourSqlConn;
yourCommand.Parameters.Add("#yourParam");
yourCommand.Parameters["#yourParam"].Direction = ParameterDirection.Output;
// execute your query successfully
int yourResult = yourCommand.Parameters["#yourParam"].Value;
You need to close the connection before you can use the output parameters.
Something like this
con.Close();
MessageBox.Show(cmd.Parameters["#code"].Value.ToString());
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
I've done some research before posting this question and I'm aware of the fact that when there's no data returned, ExecuteScalar will throw a System.NullReferenceException. That is why I modified my stored proc to "return 1" so there's guaranteed a return value. However, I'm still getting the NULL reference exception.
So I tried to use the SqlCommand to query a table that has data:
SqlCommand sqlCommand = new SqlCommand("SELECT * FROM ATableThatHasValues", conn)
When I ran execute scalar I was able to pick up a value so I know I have permission to query the database. I'm suspecting that this is some specific storeed proc permission setting that I missed?
I'd really appreciate any comment/suggestions as I've been stuck on this for a day now. :(
My code looks like this:
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
sqlConnection.Open();
using (SqlCommand sqlCommand = new SqlCommand("GetSomeValue", sqlConnection))
{
sqlCommand.CommandType = CommandType.StoredProcedure;
//sqlCommand.Parameters.Add(new SqlParameter("#Id", this.ID));
//sqlCommand.Parameters.Add(new SqlParameter("#State", 1 /* active */));
byte retValue = (byte)sqlCommand.ExecuteScalar();
return retValue;
}
}
THANKS!
I'm just going to elaborate on what #gbn said. When you execute SQL code you can return information in three different ways, OUTPUT parameters, tabular data and/or a single RETURN value. Like #gbn said, RETURN values are essentially specialized OUTPUT parameters. ExecuteScalar only sees information from tabular data, namely the first column of the first row. If no tabular data is received when you call ExecuteScalar a null value is returned instead. If you try to do something with this null value then obviously you'll get a NRE.
Random guess
You are using RETURN so there is no dataset to read column 1, row 1 for ExecuteScalar
Use SELECT or OUTPUT parameters
Edit: Actually, not so random
RETURN 1 is not a result set: it's a "special" parameter
sqlCmd.Parameters.Add(New SqlParameter("RETURN_VALUE", SqlDbType.Int)).Direction = ParameterDirection.ReturnValue