update error handling in C# - c#

I have a customer table in sqlserver which contains a rowversion field and I am incrementing it everytime I update the record,
I just have to check with
if(Customer.rowversion=#roeversion ) where customerID=#customerID
execute the update.
else RAISERROR('Update cannot be executed. There is a row version conflict.', 16, 1)
So have to now pass an out param from my c# code and return the error value. and also
- Get the Error Code for the statement just executed.
SELECT #ErrorCode=##ERROR
So how should I return the value from SQLSERVER update query into my c# code so that I can display the message.

If you're calling your sproc via ado.NET, then the SqlParameter you pass to the sproc would be set up like this:
SqlParameter P = new SqlParameter("Name of your column", SqlDbType.Int);
P.Direction = ParameterDirection.Output;
//call your sproc
int result = (int)P.Value;
EDIT
Since you're using Linq-to-SQL, adding this sproc into the methods sections should create a c# method signature for this sproc with the out parameter added for you.

If you do not already, you should have your database code in a stored procedure. The stored procedure would look something like:
CREATE PROCEDURE s_my_procedure
#RowVersion int ,
#CustomerID int ,
... additional fields here
#ErrorCode INT OUTPUT
AS
IF EXISTS(SELECT 1
FROM Customer
WHERE RowVersion = #RowVersion
AND CustomerID = #CustomerID)
BEGIN
UPDATE Customer
SET ...
WHERE RowVersion = #RowVersion
AND CustomerID = #CustomerID
SET #ErrorCode = 0
END
ELSE
BEGIN
SET #ErrorCode = 1234 -- Something meaningful to your app
END
You should try to avoid raising errors whenever possible.
Then, assuming you have a stored procedure executed by a command:
cmd.ExecuteNonQuery();
int ErrorCode = 0;
// Note that if you are not sure about your sp, you should test this for dbnull.value first
ErrorCode = Convert.ToInt32(cmd.Parameters["#ErrorCode"].Value);

Related

Why MySQL return is always 1 in C# code but not when I test in stored procedure?

I am developing an ASP.net application using MySQL and have a question related to a stored procedure return value.
This is my stored procedure:
CREATE DEFINER=`pcg`#`%` PROCEDURE `UpdatePreSellerProfile`(
IN UserID INT(11),
IN SellerImageID INT(11),
IN BusinessImageID INT(11),
OUT ProfileUpdated INT(1)
)
BEGIN
SET #Approved = 'APPROVED';
UPDATE user SET
SELLER_IMAGE_ID = COALESCE((SELECT IMAGE_ID FROM image_url WHERE IMAGE_USER_ID = UserID AND IMAGE_ID=SellerImageID),SELLER_IMAGE_ID),
SELLER_BUSINESS_LOGO_ID = COALESCE((SELECT IMAGE_ID FROM image_url WHERE IMAGE_USER_ID = UserID AND IMAGE_ID=BusinessImageID),SELLER_BUSINESS_LOGO_ID)
WHERE (USER_LOGIN_ID = UserID AND USER_PROFILE_STATUS = #Approved);
SET ProfileUpdated = ROW_COUNT();
END
When I test this code with following MySQL script I get 0 (#ProfileUpdated) always when there is no update.
call UpdatePreSellerProfile(#UserID, #SellerImageID, #BusinessImageID ,#ProfileUpdated);
But when I check this in my C# code, it is always showing 1 (ProfileUpdated).
if (oMySQLConnecion.State == System.Data.ConnectionState.Open)
{
MySqlCommand oCommand = new MySqlCommand("UpdatePreSellerProfile", oMySQLConnecion);
oCommand.CommandType = System.Data.CommandType.StoredProcedure;
MySqlParameter sqlProfileUpdated = new MySqlParameter("#ProfileUpdated", MySqlDbType.VarString);
sqlProfileUpdated.Direction = System.Data.ParameterDirection.Output;
oCommand.Parameters.Add(sqlProfileUpdated);
oCommand.Parameters.AddWithValue("#UserID", UserID);
oCommand.Parameters.AddWithValue("#SellerImageID", oSeller.SellerImageID);
oCommand.Parameters.AddWithValue("#BusinessImageID", oSeller.BusinessLogoID);
oCommand.ExecuteNonQuery();
Int16 ProfileUpdated = Convert.ToInt16(oCommand.Parameters["#ProfileUpdated"].Value);
if (ProfileUpdated > 0) // <<-- Should be greater only if it is updated is sucessfull
{
oDBStatus.Type = DBOperation.SUCCESS;
oDBStatus.Message.Add(DBMessageType.SUCCESSFULLY_DATA_UPDATED);
}
else
{
oDBStatus.Type = DBOperation.ERROR;
oDBStatus.Message.Add(DBMessageType.ERROR_NO_RECORDS_UPDATED);
}
oMySQLConnecion.Close();
}
Why is the difference between MySQL script vs C# code?
Unless you have set the UseAffectedRows connection string option, it defaults to false. This means:
When false (default), the connection reports found rows instead of changed (affected) rows. Set to true to report only the number of rows actually changed by UPDATE or INSERT … ON DUPLICATE KEY UPDATE statements.
Additionally, from the documentation of the ROW_COUNT function:
For UPDATE statements, the affected-rows value by default is the number of rows actually changed. If you specify the CLIENT_FOUND_ROWS flag to mysql_real_connect() when connecting to mysqld [ed. note: this is the same as UseAffectedRows], the affected-rows value is the number of rows “found”; that is, matched by the WHERE clause.
Thus, the UPDATE user statement in your stored procedure will return the number of rows that were found by the query, not the number that were actually updated.
To fix this, either:
Set UseAffectedRows=true; in your connection string; this may cause changes to other UPDATE queries.
Add more conditions to the WHERE clause, e.g., WHERE ... AND SELLER_IMAGE_ID != SellerImageID AND SELLER_BUSINESS_LOGO_ID != BusinessImageID, to make sure the row is only found and updated if it actually needs to change.

SQL Server stored procedure returns -1 in codebehind

I am not able to figure out what could be the reason for getting -1 for my stored procedure.
Here code behind code (C#):
SqlCommand _command = _connection.CreateCommand();
_command.CommandText = "usp_ZX_GetValidToken";
_command.CommandType = CommandType.StoredProcedure;
_command.Parameters.AddWithValue("#tokenstring", tokenString);
_command.Parameters.AddWithValue("#difference", lifeInSeconds);
Object _response = _command.ExecuteNonQuery();
Here is my stored procedure code:
CREATE procedure [dbo].[usp_ZX_GetValidToken]
#tokenstring nvarchar(50), #difference int
AS
IF EXISTS(SELECT * FROM AppAccessTokens
WHERE Consumed = 0 AND GUIDToken = RTRIM(#tokenstring)
AND DATEDIFF(SECOND, CreateDateTime, GETDATE()) <= #difference)
RETURN 1;
ELSE
RETURN -1;
Oh yes! I also make sure that my table have correct data, and I always execute below code before calling procedure:
update AppAccessTokens
set CreateDateTime = GETDATE()
The _response from the above C# code is always -1, I am really not able to figure out this on my own. I need a fresh eye to this one.
I have tried restarting machine, server, and IIS. (I know its doesn't make sense) But nothing changes, it keeps returning -1 at all times.
Can anyone suggest what should I do?
That's because when your SP is executed it will not affect any rows so ExecuteNonQuery will return 0 always. Change your SP like this:-
IF EXISTS(SELECT * FROM AppAccessTokens WHERE Consumed = 0
AND GUIDToken = RTRIM(#tokenstring) AND
DATEDIFF(SECOND, CreateDateTime, GETDATE()) <= #difference)
SELECT 1;
ELSE
SELECT -1;
Then execute it with ExecuteScalar which will read the first row of first column and we are only selecting 1 value in our SP so _response will get correct value:-
int _response = Convert.ToInt32(_command.ExecuteScalar());
Alternatively, you can also use Output parameters.

Return multiple values from Stored Procedure in C#

I need to return 2 values from stored procedure in my application. Below is the code snippet in my application. I need to get the values of SureveyID & InputID below after the respective insert statements.
int surveyId = 0;
int inputId = 0;
SqlDataManager manager = new SqlDataManager();
manager.AddParameter("#Name", surveyInstance.SurveyName);
manager.AddParameter("#Type", surveyInstance.SurveyType);
manager.AddParameter("#UserId", surveyInstance.UserId);
manager.AddParameter("#InputType", surveyInstance.InputType);
manager.AddParameter("#DisplayName", surveyInstance.DisplayName);
manager.AddOutputParameter("#SurveyID",System.Data.DbType.Int32,surveyId);
manager.AddOutputParameter("#InputID", System.Data.DbType.Int32,inputId);
manager.ExecuteNonQuery("pr_CreateSurvey");
AddParameter & AddOutputParameter is custom method as below
public void AddParameter(string parameterName, DbType parameterType, object parameterValue)
{
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = parameterName;
parameter.DbType = parameterType;
parameter.Value = parameterValue;
parameters.Add(parameter);
}
public void AddOutputParameter(string parameterName, DbType parameterType, object parameterValue)
{
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = parameterName;
parameter.DbType = parameterType;
parameter.Value = parameterValue;
parameter.Direction = ParameterDirection.Output;
parameters.Add(parameter);
}
Below is code snippet from stored procedure
ALTER PROCEDURE [dbo].[pr_CreateSurvey]
-- Add the parameters for the stored procedure here
#Name varchar(50),#Type varchar(50),#UserId varchar(50),#InputType varchar(50),#DisplayName varchar(50),
#SurveyID int OUTPUT,#InputID int OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
Insert into surveys(name,user_id,display_name,type) values(#Name,#UserId,#DisplayName,#Type)
SET #SurveyID = SCOPE_IDENTITY()
Insert into input_types(name) values (#InputType)
SET #InputID = SCOPE_IDENTITY()
END
The insert statements are working fine but I am not getting back any value in my application. Its 0.
I tried returning 1 value(SurveyID) by using below statement but still not getting correct value. Its returning -1 everytime.
surveyId = manager.ExecuteNonQuery("pr_CreateSurvey");
I tried a lot but no luck. Please advise.
find the values of the output parameters in the Parameters collection of your SqlCommand ... like
mySqlCommand.Parameters["#SurveyID"].Value
after you executed
mySqlCommand.ExecuteNonQuery();
Keep a variable of your ouput parameters around and check the .Value afterwards. The ouput gets written to the parameter, but due to boxing, it does not get written to your int. Basically, your int was copied into the parameter and your original variables do not change.
ExecuteNonQuery returns the number of rows affected, not anything else.
I've never used output parameters in my stored procedures for this. What I usually do is select out the values I want to return.
So after you do this:
SET #SurveyID = SCOPE_IDENTITY()
SET #InputID = SCOPE_IDENTITY()
I will do this
select #SurveyID as SurveyID,#InputID as InputID
Of course I'll declare those variables within the stored procedure and not as OUTPUT
This should give you what you want. If it's the correct way? Not sure. But it sure as hell works and is easy ;)

Parameter does not exist as a stored procedure parameter

ALTER PROCEDURE [dbo].[SelectCompletionNonCompletionCourseReport]
#LearnerName NVARCHAR(510) = NULL,
#ManagerId INT = NULL,
#CourseId INT = NULL,
#StartDateFrom SMALLDATETIME = NULL,
#StartDateTo SMALLDATETIME = NULL,
#TeamList XML = NULL,
#JobID NVARCHAR(max)=NULL,
#CourseStatus NVARCHAR(20)=NULL,
#ReportAdminID INT=0,
#ReportTeamList NVARCHAR(max)=NULL,
#RowsTotal int = 0,
#PageIndex int = 1,
#RowsPerPage int = 10
AS
BEGIN
DECLARE #TblCrieiria TABLE
(
id INT IDENTITY(1, 1),
areacode NVARCHAR(11),
regioncode NVARCHAR(11),
teamcode NVARCHAR(11)
)
IF #TeamList IS NULL
BEGIN
INSERT INTO #TblCrieiria VALUES(NULL,NULL,NULL)
END
BEGIN
This is the beginning of the procedure...
using (Database db = new Database(DScape.DAL.Config.ConfignPropertyName.DSCAPELMS_CONNECTION_STRING_NAME))
{
var cmd = new SqlCommand
{
CommandText = "SelectCompletionNonCompletionCourseReport",
CommandType = CommandType.StoredProcedure
};
cmd.Parameters.AddWithValue("#LearnerName", LearnerName);
cmd.Parameters.AddWithValue("#ManagerId", ManagerId);
cmd.Parameters.AddWithValue("#CourseId", CourseId);
cmd.Parameters.AddWithValue("#StartDateFrom", StartDateFrom);
cmd.Parameters.AddWithValue("#StartDateTo", StartDateTo);
cmd.Parameters.AddWithValue("#TeamList", TeamList);
cmd.Parameters.AddWithValue("#JobID", JobID);
cmd.Parameters.AddWithValue("#CourseStatus", CourseStatus);
cmd.Parameters.AddWithValue("#ReportAdminID", ReportAdminID);
cmd.Parameters.AddWithValue("#ReportTeamList", ReportTeamList);
cmd.Parameters.AddWithValue("#PageIndex", 1);
DataSet dsClient = db.GetDataSet(cmd);
if (dsClient.Tables.Count > 0)
return dsClient.Tables[0];
else
return null;
}
This is the method which communicates with the procedure, and it gaves me an error
Parameter does not exist as a stored procedure parameter/ function/procedure take too many arguments...
It's about #PageIndex parameter. Doesn't matter what is the value, we don't talk for values here but for parameter which is defined in the stored procedure but doesn't work?
And for the record, this problem did pop-up today w/o any code writing/modifying just appeared as I tried to do that report, when yesterday it was all good...I have a teammate which is next to me with absolute the same code both in sql and c# and it works just fine on his pc, but mine throws this errors, I'm trying to resolve this from 3 hours and I am completely out of answers , so please give me direction in which should I continue to resolve this .....................
and I say again, the problem is not from the connection to DB or type of the parameter or the value, the error is committed with the parameter itself - does not exist in the procedure, which is insane in my opinion.
Given that all parameters are optional, you are not required to explicitly provide any of them from your client code. Default values will be provided for you by SQL Server. The contract explictly states it in the stored procedure's signature.
An optional parameter is exactly that: optional. If you had provided the incorrect number of parameters, SQL Server would have returned a different error, indicating that the number of parameters was incorrect. This is not the case. Instead, you are seeing that you are asking for a parameter that is undefined, which indicates that the stored procedure signature you think you are calling does not match the stored procedure signature you are actually calling.
Verify that you are both connecting to the same database instance. If you are not, verify that the stored procedure is identical on both database instances.
parameter count doesnt match. check the params again.
You have to send parameters for rowstotal and rowsperpage as well because you have declared them at the top before "begin" clause.
If you do not want to send that params and they will be just constant, please declare them below as variable or constant, not a parameter.
i.e.
CREATE PROCEDURE DeleteById
#TableName sysname,
#Id int
AS
BEGIN
DECLARE #StrId AS VARCHAR(50)
SET #StrId = CONVERT(VARCHAR(50), #Id)
--any sp code here
END
Hope this helps.

Fetch return value from a stored procedure

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.

Categories