Looking on some source code I've inherited, there's a snippet of code that calls a SQL stored procedure making an Update.
The stored procedure returns -1 in case something goes wrong:
IF ##Error <> 0
BEGIN
ROLLBACK TRAN
SELECT -1
RETURN
END
COMMIT TRAN
SELECT 0
The C# code is something like this:
System.Data.SqlClient.SqlDataReader myReader;
try{
SqlDbConnection.Open();
SqlDbCommand.Connection = SqlDbConnection;
SqlDbCommand.CommandType = System.Data.CommandType.StoredProcedure;
SqlDbCommand.CommandText = "StoredProcedured_UpdateFoo";
SqlDbCommand.Parameters.Clear();
SqlDbCommand.Parameters.Add("#FooData", SqlDbType.DateTime); SqlDbCommand.Parameters["#FooData"].Value = System.DateTime.Now.ToString("yyyy-MM-dd");
myReader = SqlDbCommand.ExecuteReader();
if (myReader.Read())
{
if (int.Parse(myReader.GetValue(0).ToString()) == -1) throw new ErrorDataTxRx("Error FOO ");
}
} finally {
if (SqlDbConnection.State != ConnectionState.Closed){
SqlDbConnection.Close();
}
if (myReader != null){
if (!myReader.IsClosed) myReader.Close();
}
}
I also see part of the same code, checking the same thing using System.Data.DataSet() with Fill method.
Is there a more elegant way to check if the returned value is -1?
Is it OK to use an ExecuteReader in this case?
Have you tried using ExecuteScalar? That's designed for queries which return a single value:
Executes the query, and returns the
first column of the first row in the
result set returned by the query.
Additional columns or rows are
ignored
As Jon correctly noted, you're actually not using the return value of the SP, but actually getting the first value of the first row, which is what ExecuteScalar would do in a simpler way.
However, in order to get the return value from the SP (e.g. from something like RETURN #i; in the SP SQL code), you need to add a new Parameter and set its direction to ReturnValue, something like this:
SqlParameter returnValueParam = new SqlParameter();
returnValueParam.DbType = DbType.Int32;
returnValueParam.IsNullable = false;
returnValueParam.Direction = ParameterDirection.ReturnValue;
SqlDbCommand.Parameters.Add(returnValueParam);
// execute SP here...
int returnValue = (int)returnValueParam.Value;
Use ExecuteNonQuery instead of the reader and you will get the number of rows affected.
Your question is not clear enough. You may need to do it with a ReturnValue like Lucero has written.
Related
I'm trying to get the max id of the table category using this code
string maxid = "";
string query = "SELECT MAX(Cat_ID) + 1 FROM Category";
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["JokerCafe"].ConnectionString);
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(query, conn);
maxid = cmd.ExecuteNonQuery().ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
conn.Close();
}
return maxid;
I run this query in sql it is returning exact value but when try to execute it from code it returns -1. Kindly guide me what's going wrong with it?
ExecuteNonQuery() will return the affected row count. For example if you are trying to execute any update statement or delete statement through ExecuteNonQuery() method then it will return the number of affected rows.
But, if you want to fetch a value from specific field then you need to try ExecuteScalar() method. It will return Object type value. Using this method you can fetch only a single value record.
object val = command.ExecuteScalar();
if (val != null)
{
//Do your stuff here.
}
ExecuteScaler is your solution
It executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored.
so do modify your code to
maxid = cmd.ExecuteScalar().ToString();
or
maxid = cmd.ExecuteScalar() as string; //to be safe side if return value is null
and you'll get the value expected from the query
So I have this stored procedure in SQL server that has this bit of SQL in it
... part of store procedure...
IF ##ERROR = 0 --AND ##ROWCOUNT = 1
BEGIN
.. dO STUFF
SELECT * FROM MyTable
RETURN 0
END
ELSE
BEGIN
RAISERROR('Something went wrong :-(', 16, 1)
RETURN -1
END
END
in my C# code where I get the data I do it like this
//Sql param used to get the return value from the store procedure
SqlParameter returnValueParam = command.Parameters.Add("#return_value", SqlDbType.Int);
returnValueParam.Direction = ParameterDirection.ReturnValue;
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
SpRetrunValue.EmailAddress = DBNulls.DBNullToString(reader["Email"], string.Empty);
... More stuff
}
reader.NextResult();
SpRetrunValue.ExternalData = new List<ExternalData>();
var ExtData = new ExternalData();
while (reader.Read())
{
ExtData.Id = DBNulls.DBNullToInteger(reader["ID"], 0);
SpRetrunValue.ExternalData.Add(intExtData);
}
//get the return code on the SP 0 for success -1 for error
SpRetrunValue.ResultCode = (int)returnValueParam.Value;
}
the problem I am having is that if I use it with command.ExecuteNonQuery(); then I can get the return value. But using as is now I can not get the return value, but I do get the result set. Is it not possible to get the return value this way? I have seen this post here on stackoverflow, but that requires me adding another param to the stored procedure, which I feel defeats the purpose of just returning a value like in my stored procedure above.
You'll have to complete processing for all rowsets before attempting to capture the Return value or OUTPUT parameters. Place SpRetrunValue.ResultCode = (int)returnValueParam.Value; after your using statement.
Understanding SQL Server Return Codes and Output Parameters
Also, this post
How to fetch the return value from a stored procedure?
I noticed that the stored procedure returns an integer on its own. I need to fetch it in C#.
You can make use of Return parameter in C# to get that value. Like as below
SqlParameter retval = sqlcomm.Parameters.Add("#return_value", SqlDbType.VarChar);
retval.Direction = ParameterDirection.ReturnValue;
sqlcomm.ExecuteNonQuery();
string retunvalue = (string)sqlcomm.Parameters["#return_value"].Value;
Note your procedure must return a value to be able to fetch it:
create procedure [dbo].[usp_GetNewSeqVal]
#SeqName nvarchar(255)
as begin
declare #NewSeqVal int
select #NewSeqVal =1
---other statement
return #NewSeqVal
end
Check Following Code:
SqlParameter retval = sqlcomm.Parameters.Add("#b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.ReturnValue;
sqlcomm.ExecuteNonQuery(); // MISSING
string retunvalue = (string)sqlcomm.Parameters["#b"].Value;
For further reference check link: Getting return value from stored procedure in C#
In your SP, you need to return KategoriId. By default SP returns the number of rows affected by the latest insert, update or delete statement.
And mke sure you use proper data type in C# and in database column KategoriId to make this work. I had problems in past when database column was Decimal and I tried to assign the return value to an int and it never worked.
You can use output parameter in store procedure or use ExecuteScalar instead of ExecuteNonQuery.
Query always return -1 don't know why. Will someone please explain. Value of count always remains -1.
string query = "SELECT COUNT(*) AS Emails FROM users";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("#email", email);
try
{
connection.Open();
count = command.ExecuteNonQuery();
if (count > 0)
return "Something Wrong1";
}
catch
{
return "Something Wrong2";
}
return count + "Every thing ok";
}
That is because ExecuteNonQuery does not return the result of the query, it just executes it on the SQL server. The return value is the number of rows affected by your statement, -1 when the statement does not affect any rows. ExecuteNonQuery (as the name implies) is not intended for returning query results, but rather for running a statement that changes data (such as INSERT, DELETE, UPDATE). The docs state:
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. (...) For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
You could use:
count = (int)command.ExecuteScalar();
To get the count you are looking for. There is also an example in the docs for ExecuteScalar.
You need ExecuteScalar not ExecuteNonQuery to retrieve the count value.
I think that perhaps what you mean is for your SQL statement to be:
SELECT COUNT(*) FROM users WHERE Email = #email
Besides that, you must use the ExecuteScalar method to retrieve the count.
I'm no C# expert, but that command.ExecuteNonQuery() doesn't seem right ... it's a query after all!
Here's my SQL:
IF (SELECT Status FROM dbo.Coupon WHERE Guid = #pGuid) = 0
BEGIN
UPDATE
dbo.Coupon
SET
Status = #pStatus
WHERE
Guid = #pGuid
RETURN 0
END
ELSE
RETURN 1;
And here's my C#:
try
{
DbCommand command = db.GetStoredProcCommand("upd_Coupon_p");
db.AddInParameter(command, "#pGuid", DbType.String, s);
db.AddInParameter(command, "#pStatus", DbType.Byte, 1);
ds = db.ExecuteDataSet(command);
}
How can I get the return value of 0 or 1 inside of my code?
You add a return value parameter, like this:
For SqlCommand:
parameters.Add("#retValue", DbType.Int32, ParameterDirection.ReturnValue);
For the EL, you'd want to use db.AddParameter() and specify ParameterDirection.ReturnValue.
In addition, as long as row count is on in your database, for the update you are performing you could use the result from ExecuteNonQuery() that tells you how many rows were affected on an update/insert/delete/etc. That way you could handle if rows affected was 0 (couldn't find any)
This is what I did, so basically just use ReturnValue, but the other parts may be useful.
var retparam = new SqlParameter("#return", System.Data.SqlDbType.Int) { Direction = System.Data.ParameterDirection.ReturnValue };
comm.Parameters.Add(retparam);
comm.ExecuteNonQuery();
int ret = 0;
if (retparam == null)
{
System.Diagnostics.Debug.WriteLine("retparam was null");
}
else if (retparam.Value == null)
{
}
else
{
// use reparam.Value.ToString()
}
What is DbCommand.ExecuteDataSet() and why don't you use ExecuteScalar()?
Declare a variable as output and get it inside the call function of Data Access section.
see the code below,
In the stored procedure,
#ReturnStatus int output //inside your stored procedure argument section
In the Data Access section use the following,
AddOutParameter(.....);
Hope this helps..