C# Stored Procedure Return Scalar - c#

I have a stored procedure that will return either a 1 or 0. I cannot seem to properly wrap it in a C# function. Any help is appreciated.
Here is my stored procedure (that I've tested in SQL Server and it works):
CREATE PROCEDURE VerifyAccount
#Email VARCHAR(50),
#Pass VARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Salt CHAR(25);
DECLARE #PwdWithSalt VARCHAR(125);
DECLARE #PwdHash VARBINARY(20);
SELECT #Salt = Salt, #PwdHash = Pass
FROM users
WHERE EMAIL = #Email;
SET #PwdWithSalt = #Salt + #Pass;
IF (HASHBYTES('SHA1', #PwdWithSalt) = #PwdHash)
RETURN 1;
ELSE
RETURN 0;
END;
If I open up a new SQL query and run this code, it works:
DECLARE #Result INT;
EXEC #Result = VerifyAccount
#Email = 'myemail#email.com', #Pass = 'Str0ngP#ssw0rd!';
SELECT #Result;
When I try to wrap it in C# code, It returns a -1 value, which is not possible with this procedure. It should return a "1". What am I doing wrong?
public static int ValidateUser(User user)
{
int result = 0;
using (SqlConnection conn = new SqlConnection(SQLQuery.connDb))
{
using (var command = new SqlCommand("VerifyAccount", conn)
{
CommandType = CommandType.StoredProcedure,
Parameters =
{
new SqlParameter("#Email", user.Email),
new SqlParameter("#Pass", user.Password)
}
})
{
try
{
conn.Open();
result = command.ExecuteNonQuery();
conn.Close();
}
catch (Exception e)
{
result = -15;
Console.WriteLine(e.Message);
}
finally
{
if (conn.State == ConnectionState.Open)
{
conn.Close();
}
}
}
}
return result;
}

ExecuteNonQuery returns the number of rows affected
You need
result = (int)command.ExecuteScalar();

Here is how you read the return value fro Stored Procedures.
public static int ValidateUser(User user)
{
int result = 0;
using (SqlConnection conn = new SqlConnection(SQLQuery.connDb))
{
using (var command = new SqlCommand("VerifyAccount", conn)
{
CommandType = CommandType.StoredProcedure,
Parameters =
{
new SqlParameter("#Email", user.Email),
new SqlParameter("#Pass", user.Password)
}
})
{
try
{
// STEP 01: **** SETUP UP RETURN VALUE STORED PROCEDURES *****
var returnParameter = command.Parameters.Add("#ReturnVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
conn.Open();
result = command.ExecuteNonQuery();
// STEP 02: **** READ RETURN VALUE *****
var result = returnParameter.Value;
conn.Close();
}
catch (Exception e)
{
result = -15;
Console.WriteLine(e.Message);
}
finally
{
if (conn.State == ConnectionState.Open)
{
conn.Close();
}
}
}
}
return result;
}

Related

How to insert list of items Using Ado.net C#?

I have a store procedure which is taken 2 parameter 1st projectId and 2nd Userid
But i have to mapped the list to that particular project using single connection but i could not figure out how to insert whole list.
internal bool MapEmployeesToProject(int projectId, List<Users> lstUserToMap)
{
int value = 0;
bool check = true;
SqlConnection conn = new SqlConnection(VSTMConfigurations.ConnectionString);
using (conn)
{
SqlParameter[] param = new SqlParameter[2];
param[0] = new SqlParameter("#ProjectId",projectId );
param[1] = new SqlParameter("#ProjectDetails", );
// if there is a single user than i could pass userid here
// i am phasing a problem how to pass whole listOfUsers
using (SqlCommand cmd1 = CreateCommand(conn, param))
{
cmd1.CommandText = "sp_MapProject";
try
{
conn.Open();
SqlTransaction transaction = conn.BeginTransaction();
cmd1.Transaction = transaction;
try
{
value = Convert.ToInt32(cmd1.ExecuteNonQuery());
if (value > 0)
{
transaction.Commit();
check = true;
}
else
{
transaction.Rollback();
check = false;
}
}
catch (Exception ex1)
{
transaction.Rollback();
check = false;
}
finally
{
transaction.Dispose();
}
}
catch (Exception ex)
{
check = false;
}
}
}
return check;
}
the store procedure is
sp_MapProject
(#ProjectId int,#UserId int)
as
begin
Insert into ProjectUsers values (#ProjectId,#UserId)
end
help please!!
You can define a user define table type in your database with projectId and Userid columns. Then you can use DataTable to pass data to stored procedure.
e.g. http://www.codeproject.com/Articles/412802/Sending-a-DataTable-to-a-Stored-Procedure
Thanks!

Can't delete record when calling Stored Procedure from Web Service

I have the following stored procedure inside a package:
PROCEDURE DELETE_RECORD(serial IN NUMBER, code IN NUMBER, brand IN VARCHAR2, response OUT VARCHAR2) IS
BEGIN
DELETE FROM CWPESME.cwpesme_campaign_subsc
WHERE
sku = serial
AND id = code
AND mfg = brand;
COMMIT;
response := 'SUCCESS';
EXCEPTION WHEN OTHERS THEN
response := 'FAILURE '||SQLERRM;
END DELETE_RECORD;
This is how I call it from a web service:
[WebMethod]
public string del_record(int serial, int code, string brand)
{
using (OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings["cs"].ConnectionString))
{
using (OracleCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "MyPackage.DELETE_RECORD";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("sku", OracleType.Number, 38).Direction = System.Data.ParameterDirection.Input;
cmd.Parameters["sku"].Value = serial;
cmd.Parameters.Add("id", OracleType.Number, 38).Direction = System.Data.ParameterDirection.Input;
cmd.Parameters["id"].Value = code;
cmd.Parameters.Add("mfg", OracleType.VarChar, 250).Direction = System.Data.ParameterDirection.Input;
cmd.Parameters["mfg"].Value = brand;
cmd.Parameters.Add("response", OracleType.VarChar, 550).Direction = System.Data.ParameterDirection.Output;
try
{
conn.Open();
cmd.ExecuteNonQuery();
string result = cmd.Parameters["response"].Value.ToString();
return result;
}
catch (Exception ex)
{
string result = cmd.Parameters["response"].Value.ToString();
return (result != string.Empty) ? result : "[FAILURE] " + ex.ToString();
}
}
}
}
I'm able to remove the record if I call the stored procedure directly, but unable to do so when calling from a web service. I can however SELECT and UPDATE in this way. What's happening?
There was nothing wrong with the code; the user was re-checked and granted all privileges over the table and now is able to delete rows.

C# Scope_Identity Issue

Browsed some answers and doesn't appear to be working for me.
I need the ID field of a table to be returned so I can use it in a different part of the program, I've tried using
Convert.ToInt32(sqlComm.ExecuteScalar());
But no luck, and same for
Convert.ToInt32(sqlComm.Parameters["ID"].Value);
And both return 0, even though the record does get inserted into the table.
I'll dump the code below, can anyone see what I'm doing wrong?
using (SqlConnection sqlConnect = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
{
using (SqlCommand sqlComm = new SqlCommand("up_Insert_Address", sqlConnect))
{
sqlComm.CommandType = CommandType.StoredProcedure;
sqlComm.Parameters.Add("#AddressID", SqlDbType.BigInt).Direction = ParameterDirection.Output;
sqlComm.Parameters.Add("#AddressLineOne", SqlDbType.NVarChar, 40).Value = address.AddressLineOne;
try
{
sqlComm.Connection.Open();
return Convert.ToInt32(sqlComm.ExecuteScalar());
}
catch (SqlException)
{
}
finally
{
sqlComm.Connection.Close();
}
}
}
And Stored Procedure:
#AddressID Bigint OUTPUT,
#AddressLineOne NVarChar(40)
AS
BEGIN
BEGIN TRY
INSERT INTO Address
(
AddressLineOne
)
VALUES
(
#AddressLineOne
)
SET #AddressID = SCOPE_IDENTITY();
END TRY
BEGIN CATCH
DECLARE #Err nvarchar(500)
SET #Err = ERROR_MESSAGE()
RAISERROR(#Err, 16, 1)
END CATCH
END
You should be using
Convert.ToInt64(sqlComm.Parameters["#AddressID"].Value);
after you execute the command using ExceuteNonQuery. For future reference, ExecuteScalar returns the first column of the first row in the result set returned by the query. You're not returning anything, just setting the value of an OUTPUT parameter.
Also you should DEFINITELY not swallow any SqlException. Since your command and connection are already in using blocks you don't need to add another try/catch/finally. Change it to to:
//try
//{
sqlComm.Connection.Open();
sqlComm.ExecuteNonQuery();
return Convert.ToInt64(sqlComm.Parameters["#AddressID"].Value);
// using Int64 since the SQL type is BigInt
//}
//catch (SqlException)
//{
//}
//finally
//{
// sqlComm.Connection.Close();
//}
var connectionstring = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
var addressId = 0L; // long value (64bit)
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand("up_Insert_Address", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#AddressID", addressId);
command.Parameters.AddWithValue("#AddressLineOne", address.AddressLineOne);
command.Parameters["#AddressID"].Direction = ParameterDirection.Output;
try
{
if(connection.State != ConnectionState.Open)
connection.Open();
var rowsAffected = command.ExecuteNonQuery();
addressId = Convert.ToInt64(command.Parameters["#AddressID"].Value);
}
catch (SqlException)
{
// Handle SQL errors here.
}
}

problem to save data in a SQL database from a results table via web service

I have a problem and I need your help. As my web service describes I want to get some data and add them to my database.
[WebMethod(Description = "This will input computers into the database", EnableSession = false)]
public string orderItem(int CUS_ID, string COM_ID, int Quantity,double COMPrice)
{
try
{
dbConn = new DbConnection();
SqlConnection conn = dbConn.OpenConnection();
SqlCommand orderItem = new SqlCommand("OrderComputer", conn);
orderItem.CommandType = CommandType.StoredProcedure;
SqlParameter add_CUS_ID = orderItem.Parameters.Add("#CUS_ID", SqlDbType.Int, 4);
add_CUS_ID.Value = CUS_ID;
SqlParameter addBK_ISBN = orderItem.Parameters.Add("#COM_ID", SqlDbType.Char, 80);
addBK_ISBN.Value = COM_ID;
SqlParameter add_Quantity = orderItem.Parameters.Add("#Quantity", SqlDbType.Int, 2);
add_Quantity.Value = Quantity;
SqlParameter add_COMPrice = orderItem.Parameters.Add("#COMPrice", SqlDbType.Money, 8);
add_COMPrice.Value = COMPrice;
return this.ExecuteQuery(orderItem);
}
catch (Exception e)
{
return e.ToString();
}
}
The OrderComputer is a stored procedure:
ALTER Procedure OrderComputer
(
#CUS_ID int,
#COM_ID int,
#Quantity int,
#COMPrice money
)
AS
declare #Date datetime
declare #ShipDate datetime
declare #OR_ID int
select #Date = getdate()
select #ShipDate = getdate()
begin tran NewComputer
INSERT INTO Orders
(
CUS_ID,
Date,
ShipDate
)
VALUES
(
#CUS_ID,
#Date,
#ShipDate
)
SELECT #OR_ID = ##Identity
INSERT INTO ComputerOrders
(
OR_ID,
COM_ID,
Quantity,
COMPrice
)
VALUES
(
#OR_ID,
#COM_ID,
#Quantity,
#COMPrice
)
commit tran NewComputer
The following part is the final step of my shopping cart. It returns a table with the order details. My problem is why the line
order.orderItem(customerID, Computer_ID, quantity, price);
cannot get the record to add it to the database?. Is something missing?
computerOrder1.computerOrder order = new computerOrder1.computerOrder();
int quantity = 2;
XmlDocument customer_Order = ComputerCart.getCartDescription();
while (customer_Order.SelectNodes("//Computers").Count > 0)
{
string Computer_ID = customer_Order.GetElementsByTagName("Computers").Item(0).SelectSingleNode("//com_id").InnerText;
double price = double.Parse(customer_Order.GetElementsByTagName("Computers").Item(0).SelectSingleNode("//price").InnerText);
string Model = customer_Order.GetElementsByTagName("Computers").Item(0).SelectSingleNode("//model").InnerText;
order.orderItem(customerID, Computer_ID, quantity, price);
}
Juding by your comment:
protected string ExecuteQuery(SqlCommand QueryObject) {
int queryResult = QueryObject.ExecuteNonQuery();
if (queryResult != 0) {
return "Your request is CORRECT";
}
else {
return "error: QueryResult= " + queryResult;
}
}
You would need not only your SqlCommand but also your connection
protected string ExecuteQuery(SqlCommand QueryObject, SqlConnection conn) {
try
{
conn.open();
int queryResult = QueryObject.ExecuteNonQuery();
if (queryResult != 0) {
return "Your request is CORRECT";
}
else {
return "error: QueryResult= " + queryResult;
}
}
finally
{
conn.close();
}
}

Problem Error Handling in Stored Statement?

Here is my stored procedure on updating records :
ALTER
PROCEDURE [dbo].[sp_UpdatetoShipped]
(
#Date datetime,
#SerialNumber
varchar(50),
#User
varchar(50),
#WorkWeek
varchar(50)
)
AS
BEGIN
UPDATE dbo.FG_FILLIN SET Status='SHIPPED',DateModified=#Date,ModifiedBy=#User,WorkWeek=#WorkWeek where (Status='KITTED')and SerialNumber=#SerialNumber
END
Then this is my DAL:
public int UpdatetoShipped(FillinEntity fin)
{
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
SqlCommand cmd = new SqlCommand("sp_UpdatetoShipped", conn);
cmd.CommandType =CommandType.StoredProcedure;
try
{
cmd.Parameters.Add("#SerialNumber", SqlDbType.VarChar,50).Value = fin.SerialNumber;
cmd.Parameters.Add("#WorkWeek", SqlDbType.VarChar, 50).Value = fin.WorkWeek;
cmd.Parameters.Add("#Date", SqlDbType.DateTime).Value = DateTime.Now.ToString();
cmd.Parameters.AddWithValue("#User", fin.ModifiedBy);
return cmd.ExecuteNonQuery();
}
catch
{
throw;
}
finally
{
cmd.Dispose();
conn.Close();
conn.Dispose();
}
}
My BLL:
public int UpdatetoShipped(FillinEntity fin)
{
DAL pDAL = new DAL();
try
{
return pDAL.UpdatetoShipped(fin);
}
catch
{
throw;
}
finally
{
pDAL = null;
}
}
And MY UI:
string filepath2 = txtPath2.Text;
Stream stream2 = new FileStream(filepath2, FileMode.Open, FileAccess.Read, FileShare.Read);
ExcelMapper<FillinEntity> exceltoshipped = new ExcelMapper<FillinEntity>();
IExcelParser excelParser2 = new ExcelReaderExcelParser(stream2);
IExcelRowMapper<FillinEntity> mapper2 = new ShippedRowMapper();
IEnumerable<FillinEntity> fillin2 = exceltoshipped.ListAll(excelParser2, mapper2);
int intResult = 0;
BAL pBAL = new BAL();
try
{
foreach (FillinEntity fin in fillin2)
{
fin.ModifiedBy = loggedUser;
intResult = pBAL.UpdatetoShipped(fin);
}
if (intResult > 0)
MessageBox.Show("Record Updated Successfully.");
else
MessageBox.Show("Record couldn't Updated Check Serial");
}
catch (Exception ee)
{
MessageBox.Show(ee.Message.ToString());
}
finally
{
pBAL =null;
}
My problem is it always says updated succussfully. But if i updated it again as duplicate update i want to show serial is already updated.
The key change you need to make is to the following line of SQL from your stored procedure:
UPDATE dbo.FG_FILLIN
SET Status='SHIPPED',
DateModified=#Date,
ModifiedBy=#User,
WorkWeek=#WorkWeek
WHERE (Status='KITTED')
AND SerialNumber=#SerialNumber
You need to return a value that allows you to determine if this UPDATE has already happened or not, for example:
DECLARE #iUpdateAlreadyComplete INT
SET #iUpdateAlreadyComplete = 0;
IF EXISTS
(
SELECT 1
FROM dbo.FG_FILLIN
WHERE Status='SHIPPED'
AND SerialNumber=#SerialNumber
)
BEGIN
SET #iUpdateAlreadyComplete = 1
END
ELSE
BEGIN
UPDATE dbo.FG_FILLIN
SET Status='SHIPPED',
DateModified=#Date,
ModifiedBy=#User,
WorkWeek=#WorkWeek
WHERE (Status='KITTED')
AND SerialNumber=#SerialNumber
END
SELECT #iUpdateAlreadyComplete AS Result
You can then change your DAL from return cmd.ExecuteNonQuery(); to:
var result = Convert.ToInt32(cmd.ExecuteScalar());
return result;
The return value will now be 0 for a record that has been updated, and 1 for one that didn't need updating as it was already processed.
Other Notes
There are a couple of other things that you should consider changing:
sp_UpdatetoShipped is a bad name for a stored procedure. Do not use the sp_ prefix.
Your DAL deliberately catches and re-throws an exception (admittedly in the "best" way), do you really need to?
Rather than explicitly calling Dipose(), use the using() {} syntax instead, as this ensures that Dispose() is called, even in the event of an exception.
using syntax:
using(SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("sp_UpdatetoShipped", conn))
{
}
}
This seems more like a business rule issue than anything to do with an error. What you might want to do is to create a dictionary to hold serial numbers that have already been updated.
e.g.
Dictoinary<string,string> updatedSerialNumbers = new Dictionary<string, string>();
foreach (FillinEntity fin in fillin2)
{
fin.ModifiedBy = loggedUser;
if (updatedSerialNumbers.Contains(fin.SerialNumber) == false)
{
intResult = pBAL.UpdatetoShipped(fin);
updatedSerialNumbers.Add(fin.SerialNumber,fin.SerialNumber);
}
Something like this should sort out your problem.

Categories

Resources