Get resultSet and ReturnedValue from procedure - c#

I need to get resultSet and ReturnedValue from procedure.
My problem is that as i understand to get the returned value i need to execute the "ExecuteNonQuery()" and for the reader i need to execute "ExecuteReader()".
But this doesnt seems right that i call execute 2 times.
What is the currect way of doing so
using (OleDbConnection connection = new OleDbConnection(getConnetionString()))
{
using (OleDbCommand command = new OleDbCommand())
{
command.CommandText = "GamesApp.Images_Get";
command.Connection = connection;
command.CommandType = CommandType.StoredProcedure;
OleDbParameter retParameter = DBUtils.createReturnOleParam(OleDbType.Integer);
command.Parameters.Add(retParameter);
tmpParameter = DBUtils.createDBParam("#ImageID", OleDbType.Integer, ParameterDirection.Input, id);
command.Parameters.Add(tmpParameter);
command.Connection.Open();
command.ExecuteNonQuery();
int retValue = (int) retParameter.Value;
if (retValue == 0)
using (OleDbDataReader reader = command.ExecuteReader())
{
if (reader != null)
{
while (reader.Read())
{
Debug.WriteLine(reader.GetString(1));
}
reader.Close();
}
}
connection.Close();
}
}
GamesApp.Images_Get":
ALTER PROCEDURE [GamesApp].[Images_Get]
#ImageID SMALLINT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #ErrorProc VARCHAR(500), #ErrorNumber INT, #ErrorSeverity INT, #ErrorState INT, #ErrorLine INT, #ErrorMessage VARCHAR(512)
DECLARE #ProcParams NVARCHAR(4000);
BEGIN TRY
--Check if #ImageID exists.if not error code is 1
IF NOT EXISTS (SELECT * FROM GamesApp.Images WHERE ImageID = #ImageID)
RETURN 1
SELECT ImageName, BG_Color, DisplayText, Text_Color, Text_Align, Text_Size
, ImageFormat, HtmlImageType, TheImage
FROM GamesApp.Images
WHERE ImageID = #ImageID;
RETURN 0;
END TRY
BEGIN CATCH
SELECT
#ErrorNumber = ERROR_NUMBER(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE(),
#ErrorLine = ERROR_LINE(),
#ErrorMessage = ERROR_MESSAGE(),
#ErrorProc = 'GamesApp.Images_Get',
#ProcParams = '#ImageID' + #ImageID
EXEC dbo.Log_Exceptions_Insert #ErrorProc, #ProcParams, #ErrorLine, #ErrorNumber, #ErrorSeverity, #ErrorState, #ErrorMessage;
THROW;
END CATCH
END

I think there is no need to call ExecuteNonQuery()
As mentioned by #Damith you can use OleDbDataReader.HasRows
For verification you can look here and here

Related

Procedure or function 'sp_Lab_InsertBiologicalPersonnel' expects parameter '#IcNumber', which was not supplied

I am trying to insert data into a SQL Server database by calling a stored procedure, but I am getting the error
Procedure or function 'sp_Lab_InsertBiologicalPersonnel' expects parameter '#IcNumber', which was not supplied
My stored procedure is called sp_Lab_InsertBiologicalPersonnel. I already check many time if there something missing, but still get same error, even make comparison with old code which is working. But for my code it say that error.
This is my C# code
public static PostApiResponse InsertBiologicalPersonel(Adapter ad, BiologicalPersonelInsert request, int creatorUserId)
{
var response = new PostApiResponse();
try
{
using (SqlCommand command = new SqlCommand("sp_Lab_InsertBiologicalPersonnel", ad.SQLConn, ad.SQLTran))
{
SqlParameter Param = new SqlParameter();
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter() { Value = request.biologicalId, ParameterName = "#biologicalId" });
command.Parameters.Add(new SqlParameter() { Value = request.IcNumber, ParameterName = "#IcNumber" });
command.Parameters.Add(new SqlParameter() { Value = request.Position, ParameterName = "#Position" });
command.Parameters.Add(new SqlParameter() { Value = creatorUserId, ParameterName = "#IdUserCreator" });
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
response.ResponseMessage = reader.GetString(0);
response.ReturnCode = reader.GetInt32(1);
response.Id = Convert.ToInt32(reader.GetValue(2));
}
reader.Close();
}
}
}
catch (Exception e)
{
throw e;
//string context = Common.ToStr(System.Web.HttpContext.Current);
//clsErrorLog.ErrorLog(context, e);
}
return response;
}
And this is my stored procedure:
ALTER PROCEDURE [dbo].[sp_Lab_InsertBiologicalPersonnel]
#biologicalId INT,
#IcNumber INT ,
#Position NVARCHAR(50),
#IdUserCreator INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #ReturnCode Int
DECLARE #ReturnMessage NVARCHAR(200)
DECLARE #Identity INT
INSERT INTO [dbo].[Lab_BiologicalPersonnel]
([Id]
--,[Name]
,[IcNumber]
,[Position]
,[IdUserCreator]
,[IsDeleted]
,[IsEnabled])
VALUES
(#biologicalId
--,#Name
,#IcNumber
,#Position
,#IdUserCreator
,0
,1)
IF ##ROWCOUNT = 0
BEGIN
SET #ReturnCode = 1
SET #ReturnMessage = 'Insert Fail'
SET #Identity = 0
END
ELSE
BEGIN
SET #ReturnCode = 0
SET #ReturnMessage = 'Insert Success'
SET #Identity = (SELECT SCOPE_IDENTITY())
END
SELECT #ReturnMessage, #ReturnCode, #Identity
END
Please help me explain in quite simple, I'm a newbie in programming.

Get the primary key as output or return when you performing an Update query?

I'm trying to get the output parameter of primary key which is ID. When I do the update query I get Null. Can you please suggest a way to do this?
CREATE PROCEDURE sp_InsertTax
(#ID int output,
#TaxAuthorityID int,
#TaxClassificationID int,
#EntityID int,
#AppliesTo_TaxEntityTypeID int)
AS
IF EXISTS (SELECT * FROM Tax
WHERE TaxAuthorityID = #TaxAuthorityID
AND TaxClassificationID = #TaxClassificationID
AND EntityID = #EntityID
AND AppliesTo_TaxEntityTypeID = #AppliesTo_TaxEntityTypeID)
BEGIN
UPDATE Tax
SET TaxAuthorityID = #TaxAuthorityID,
TaxClassificationID = #TaxClassificationID,
EntityID = #EntityID,
AppliesTo_TaxEntityTypeID = #AppliesTo_TaxEntityTypeID
WHERE ID = #ID
END
ELSE
BEGIN
IF #ID IS NULL
BEGIN
INSERT INTO Tax(TaxAuthorityID, TaxClassificationID, EntityID, AppliesTo_TaxEntityTypeID)
VALUES (#TaxAuthorityID, #TaxClassificationID, #EntityID, #AppliesTo_TaxEntityTypeID)
SET #ID = Scope_Identity()
END
END
GO
The below is my ADO.NET code to call the update stored procedure:
public int InsertFederalTax(int ClassificID, int appliesTo)
{
int tax_id = 0;
Sqlconn.Open();
SqlCommand cmd = new SqlCommand("sp_InsertTax", Sqlconn);
cmd.CommandType = CommandType.StoredProcedure;
var returnparameter = cmd.Parameters.AddWithValue("ID", SqlDbType.Int);
returnparameter.Direction = ParameterDirection.Output;
cmd.Parameters.Add("#TaxAuthorityID", SqlDbType.Int).Value = 1;
cmd.Parameters.Add("#TaxClassificationID", SqlDbType.Int).Value = ClassificID;
cmd.Parameters.Add("#EntityID", SqlDbType.Int).Value = 0;
cmd.Parameters.Add("#AppliesTo_TaxEntityTypeID", SqlDbType.Int).Value = appliesTo;
cmd.ExecuteNonQuery();
if (!(returnparameter.Value is DBNull))
tax_id = Convert.ToInt32(returnparameter.Value);
Sqlconn.Close();
return tax_id;
}
I think you intended to capture the ID of an existing duplicate record, which you would do as follows. I've also added best practice template items for a SP. Also note the comment from marc_c about not prefixing your SP with sp_.
CREATE PROCEDURE InsertTax
(
#ID int output
, #TaxAuthorityID int
, #TaxClassificationID int
, #EntityID int
, #AppliesTo_TaxEntityTypeID int
)
AS
BEGIN
SET NOCOUNT, XACT_ABORT ON;
-- This assumes that none of the parameters can ever be null
-- And from your comments we know that no duplicates can exist
SELECT #ID = ID
FROM Tax
WHERE TaxAuthorityID = #TaxAuthorityID
AND TaxClassificationID = #TaxClassificationID
AND EntityID = #EntityID
AND AppliesTo_TaxEntityTypeID = #AppliesTo_TaxEntityTypeID;
IF #ID IS NOT NULL BEGIN
UPDATE Tax
SET TaxAuthorityID = #TaxAuthorityID,
TaxClassificationID = #TaxClassificationID,
EntityID = #EntityID,
AppliesTo_TaxEntityTypeID = #AppliesTo_TaxEntityTypeID
WHERE ID = #ID;
END; ELSE BEGIN
INSERT INTO Tax (TaxAuthorityID, TaxClassificationID, EntityID, AppliesTo_TaxEntityTypeID)
VALUES (#TaxAuthorityID, #TaxClassificationID, #EntityID, #AppliesTo_TaxEntityTypeID);
SET #ID = SCOPE_IDENTITY();
END;
RETURN 0;
END;
GO
And I recommend declaring your return parameter as:
var returnparameter = new SqlParameter("#ID", SqlDbType.Int)
{
Direction = ParameterDirection.InputOutput
};
cmd.Parameters.Add(returnparameter);
Please, may you try to change your C# code with this updates bellow, and give us feed-back:
public int InsertFederalTax(int ClassificID, int appliesTo)
{
int tax_id = 0;
Sqlconn.Open();
SqlCommand cmd = new SqlCommand("sp_InsertTax", Sqlconn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ID", SqlDbType.Int);
cmd.Parameters["#ID"].Direction = ParameterDirection.Output;
cmd.Parameters.AddWithValue("#TaxAuthorityID", 1);
cmd.Parameters.AddWithValue("#TaxClassificationID", ClassificID);
cmd.Parameters.AddWithValue("#EntityID", 0);
cmd.Parameters.AddWithValue("#AppliesTo_TaxEntityTypeID", appliesTo);
cmd.ExecuteNonQuery();
if(!(cmd.Parameters["#ID"].Value is DBNull))
{
tax_id = Convert.ToInt32(cmd.Parameters["#ID"].Value);
}
Sqlconn.Close();
return tax_id;
}

stored procedure expect some input though its provided

I am stuck in a problem. i am getting error "Procedure or function 'SP_RPT_User' expects parameter '#deptName', which was not supplied." in c# application while parameter is provided. even i copied and replaced the name. still no success.
public DataTable SP_RPT_User(int loggedid, String deptName, String OfficeName, String empType)
{
int updatedrows = 0;
DataTable table = new DataTable();
try
{
cCommand = new System.Data.SqlClient.SqlCommand("SP_RPT_User", connection);
cCommand.CommandType = CommandType.StoredProcedure;
cCommand.Parameters.Add("#loggedId", SqlDbType.Int).Value = loggedid;
cCommand.Parameters.Add("#deptName", SqlDbType.NVarChar, 200).Value = deptName;
cCommand.Parameters.Add("#OfficeName", SqlDbType.VarChar, 150).Value = OfficeName;
cCommand.Parameters.Add("#empType", SqlDbType.VarChar, 150).Value = empType;
cCommand.CommandTimeout = 90000;
connection.Open();
updatedrows = cCommand.ExecuteNonQuery();
using (var da = new SqlDataAdapter(cCommand))
{
cCommand.CommandType = CommandType.StoredProcedure;
da.Fill(table);
}
}
catch (Exception Ex)
{
connection.Close();
// return -100;
}
finally
{
connection.Close();
}
return table;
}
Stored Procedure
ALTER PROCEDURE [dbo].[SP_RPT_User]
-- Add the parameters for the stored procedure here
#loggedId int,
#deptName NVarChar(200),
#OfficeName varchar(150),
#empType varchar(150)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #sql nvarchar(max);
set #sql ='SELECT ...'; // here is one query
if(#deptName != '')
set #sql = #sql + ' and dbo.TB_Department.name like ''%'+#deptName+'%''';
Declare #params nvarchar(500)
SELECT #params ='#loggedId int,'+
'#deptName NVarChar(200),'+
'#OfficeName varchar(150),'+
'#empType varchar(150)'
exec sp_executesql #sql, #params,#loggedId,#deptName,#OfficeName,#empType;
END
Can anyone help. thanks in advance.
i am using sql server 2014 and vs2015.
The educated guess I have is that deptName value in C# is null while you execute the query. In such case you should pass DBNull.Value to have null as parameter value:
var param = cCommand.Parameters.Add("#deptName", SqlDbType.NVarChar, 200);
param.Value = deptName ?? DBNull.Value;
From your procedure I see that you compare with empty string so use ?? string.Empty to satisfy that condition.

load Output parameters from SQL stored procedure c#

I am trying to load output parameters from my SQL stored procedure.
USE [EdiMon_Beta]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GetClients]
-- Add the parameters for the stored procedure here
#sender nvarchar(max),
#subSender nvarchar(max),
#receiver nvarchar(max),
#subReceiver nvarchar(max),
#msgTypeID int,
#ErrorMsg nvarchar(max) = null OUTPUT,
#processId int = 0 OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE
#senderId int,
#subSenderId int,
#receiverId int,
#subReceiverId int
SELECT
#senderId = ID
FROM [dbo].[Party_Client]
WHERE
[Number] LIKE #sender
IF(#senderId IS NULL)
BEGIN
SET #ErrorMsg = 'Sender does not exist'
RETURN ;
END
SELECT
#subSenderId = ID
FROM [dbo].[Party_Client]
WHERE
[Number] LIKE #subSender
AND ParentId = #senderId
AND IsSubClient = 1
IF(#subSenderId IS NULL)
BEGIN
SET #ErrorMsg = 'SubSender does not exist'
RETURN ;
END
SELECT
#receiver = ID
FROM [dbo].[Party_Client]
WHERE
[Number] LIKE #receiver
IF(#receiverId IS NULL)
BEGIN
SET #ErrorMsg = 'Receiver does not exist'
RETURN;
END
SELECT
#subReceiverId = ID
FROM [dbo].[Party_Client]
WHERE
[Number] LIKE #subReceiver
AND ParentId = #receiverId
AND IsSubClient = 1
IF(#subReceiverId IS NULL)
BEGIN
SET #ErrorMsg = 'SubReceiver does not exist'
RETURN ;
END
SELECT #processId = ID FROM [dbo].[Party_Processes]
WHERE MsgTypeId = #msgTypeID
AND SenderId = #senderId
AND ReceiverId = #receiverId
END
And reading it with c# code:
using (SqlConnection connection = new SqlConnection(connectionString))
{
try
{
SqlCommand command = new SqlCommand("GetClients", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#sender", sender));
command.Parameters.Add(new SqlParameter("#subSender", subSender));
command.Parameters.Add(new SqlParameter("#receiver", receiver));
command.Parameters.Add(new SqlParameter("#subReceiver", subReceiver));
command.Parameters.Add(new SqlParameter("#msgTypeID", msgTypeID));
var errorMsgParam = command.Parameters.Add(new SqlParameter("#ErrorMsg", SqlDbType.NVarChar, -1));
errorMsgParam.Direction = ParameterDirection.Output;
var processIdParam = command.Parameters.Add(new SqlParameter("#processId", SqlDbType.Int, -1));
processIdParam.Direction = ParameterDirection.Output;
connection.Open();
command.ExecuteNonQuery();
var processIDResult = command.Parameters["#processId"].Value;
var errorMsgResult = command.Parameters["#ErrorMsg"].Value;
processID = (int)processIDResult;
errorMsg = errorMsgResult.ToString();
}
}
The thing is, I always get null as result. This is Helper class for xsl mapping in biztalk. All the input parameters are directly from the map. I want to check our database, if these clients exist and also, if process which using them exist.
thanks for your help :)
OK, i solved this. Problem was in 2 or 3 places. For first i had mistake in my SQL stored procedure which is not universal so i didnt post it here (it applies only to my project). The other mistake was in converting my output from stored procedure:
processID = command.Parameters["#processId"].Value as int?;
errorMsg = command.Parameters["#ErrorMsg"].Value == DBNull.Value ? string.Empty : command.Parameters["#ErrorMsg"].Value.ToString();
where processID is declared as "int?" and errorMsg is declared as "string".
Thanks for all the help.

Raise user defined SQL error and capture it in code

I'm trying to raise a user defined error from one stored procedure to a c# code. I have a stored procedure that assign employees to users, if you already assigned an employee to user 1 for example and you try to do the same thing again, the stored procedure should raise an error saying, "This association already exists" and return a code, for example 1 and a description of the error. The problem is that in c sharp is not passing by the catch part. here is the code:
public bool InsertUser(Guid userId, string[][] IDs, AppParams myParams)
{
bool flag = false;
SqlTransaction transaction = null;
using (var dbConn = new SqlConnection(this.ConnectionString))
{
using (var cmd = new SqlCommand())
{
try
{
dbConn.Open();
cmd.Connection = dbConn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "InsertUser";
transaction = dbConn.BeginTransaction();
cmd.Transaction = transaction;
for (int i = 0; i < IDs.Length; i++)
{
flag = false;
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#UserId", userId);
cmd.Parameters.AddWithValue("#EmployeeId", IDs[i][0]);
cmd.Parameters.AddWithValue("#CompanyId", myParams.ApplicationId);
cmd.Parameters.AddWithValue("#ModifiedUserId", myParams.User.UserId);
//add output parameter
cmd.Parameters.Add("#ID", SqlDbType.Int, 4);
cmd.Parameters["#ID"].Direction = ParameterDirection.Output;
cmd.Parameters.Add("#ReturnValue", SqlDbType.Int, 4);
cmd.Parameters["#ReturnValue"].Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add("#ErrorMsg", SqlDbType.VarChar, 300);
cmd.Parameters["#ErrorMsg"].Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
var returnValue = Convert.ToInt32(cmd.Parameters["#ReturnValue"].Value);
flag = returnValue.Equals(0);
if (!flag)
{
if (cmd.Parameters["#ErrorMsg"].Value != DBNull.Value)
{
this.ErrorModel.HasError = true;
this.ErrorModel.ErrorMessage = cmd.Parameters["#ErrorMsg"].Value.ToString();
}
transaction.Rollback();
return false;
}
}
transaction.Commit();
}
catch (SqlException sqlex)
{
this.ErrorModel.HasError = true;
this.ErrorModel.ErrorMessage = sqlex.Message;
}
catch (Exception ex)
{
this.ErrorModel.HasError = true;
this.ErrorModel.ErrorMessage = ex.Message;
}
}
}
return flag;
}
Am I doing something wrong?
here is my SQL code:
ALTER PROCEDURE [dbo].[InsertUser]
(
#UserId uniqueidentifier,
#EmployeeId int,
#CompanyId uniqueidentifier,
#SystemStatusId int = 1,
#ModifiedByUserId uniqueidentifier,
#ID int output,
#ErrorMsg nvarchar(300) = NULL output
)
AS
BEGIN
DECLARE #ReturnVal int
SET NOCOUNT ON;
SET #ReturnVal = 0;
SET #ErrorMsg = null;
-- check for existing combination
IF EXISTS(SELECT 1 FROM [dbo].[UserRel]
WHERE [UserId] = #UserId
AND [EmployeeId] = #EmployeeId
AND [CompanyId] = #CompanyId
AND [SystemStatusId] = 1)
BEGIN
SET #ReturnVal = 1;
SET #ErrorMsg = 'Item already Exist in Database'
RAISERROR #ErrorMsg, 0, 0
GOTO ProcedureExit;
END
-- Insert statement
INSERT [dbo].[UserRel]
(
[UserId],
[EmployeeId],
[CompanyId],
[SystemStatusId],
[ModifiedByUserId],
[ModifiedDate]
)
VALUES
(
#UserId,
#EmployeeId,
#CompanyId,
#SystemStatusId,
#ModifiedByUserId,
sysdatetimeoffset()
)
IF( ##ERROR <> 0 )
BEGIN
SET #ReturnVal = 2;
SET #ErrorMsg = 'Failed to INSERT [dbo].[InsertUser]'
GOTO ProcedureExit;
END
ELSE
SET #ID = SCOPE_IDENTITY();
ProcedureExit:
RETURN #ReturnVal;
END
The problem is that in c sharp is not passing by the catch part.
Because in the C#, there was no exception. You simply checked the return value of the stored procedure, and then decided to rollback and return false;. If you want an exception: throw an exception.
Alternatively, if the SQL issues a raiserror with severity 16 or higher, an exception will be observed automatically.
Incidentally, it is not clear that your transaction is correctly terminated in the case of a genuine exception. I would suggest moving the rollback code into the catch block. Since you do the exact same thing regardless of which exception you catch, there is no benefit in the catch (SqlException sqlex) block - so you might as well remove that.

Categories

Resources