How to pass parameter for sproc via C# - c#

I have a MVC application that runs the following sproc named sp_GetEmployeeByID:
#ID int = 0
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT #ID, *
from tblEmployee
where ID = #ID
and the method that calls this needs to pass the int parameter however I cant seem to figure this out, here is what i have so far:
public Employee GetSingleEmployee(int ID)
{
string connectionString = ConfigurationManager.ConnectionStrings["KVKDb"].ConnectionString;
Employee emp = new Employee();
using (SqlConnection connect = new SqlConnection(connectionString))
{
SqlCommand sprocCmd = new SqlCommand("sp_GetEmployeeByID " + ID, connect); sprocCmd.CommandType = System.Data.CommandType.StoredProcedure;
connect.Open();
SqlDataReader rdr = sprocCmd.ExecuteReader();
while (rdr.Read() == true)
{
Employee employee = new Employee();
employee.ID = Convert.ToInt32(rdr["ID"]);
employee.City = rdr["City"].ToString();
employee.DateOfBirth = Convert.ToDateTime(rdr["DateOfBirth"]);
employee.Gender = rdr["Gender"].ToString();
employee.Name = rdr["Name"].ToString();
emp = employee;
}
}
return emp;
}
The obvious issue is that there is no sproc named sp_GetEmployeeByID int ID. I want to know how to call that sproc and pass a parameter for the sprocs #ID parameter.

Add a Parameter to the command:
SqlCommand sprocCmd = new SqlCommand("sp_GetEmployeeByID");
sprocCmd.CommandType = System.Data.CommandType.StoredProcedure;
sprocCmd.Parameters.AddWithValue("#ID", ID)

Related

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;
}

If Employee exists then return employee roles using ADO.net

The idea under REST is, if an http request may come for an unknown record, we return 404, if it exists then roles of the employee.
The naive way would be that I can do this in two SQL statements, check the result of the first return null if not found else proceed with retrieving roles. The caller can check if result of the function is null and can return 404 based on that otherwise it will dislay roles of the user.
"SELECT Id FROM Employee WHERE Id = #Id"
"SELECT * FROM Role WHERE EmployeeId = #Id"
My current implementation is:
public List<object> GetUserRolesById(int id)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
// statement 1
string sql = "SELECT Id FROM Employee WHERE Id = #Id";
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#Id", SqlDbType.Int, 32).Value = id;
using (SqlDataReader reader = command.ExecuteReader())
{
if (!reader.Read() || reader.IsDBNull(reader.GetOrdinal("Id")))
{
return null; // caller to return 404 if record not found
}
}
}
// statement 2
sql = #"SELECT Id, Name FROM Role WHERE EmployeeId = #Id";
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#Id", SqlDbType.Int, 32).Value = id;
using (SqlDataReader reader = command.ExecuteReader())
{
List<object> roles = new List<object>();
if (reader.Read())
{
for (int i = 0; i < roleIds.Length; i++)
{
roles.Add(new {Id = Int32.Parse(reader.GetString((0)), Name = reader.GetString(1)});
}
}
return roles;
}
}
}
}
Question:
How can I combine both SQL statements in one in a nicer way?
Edit
Following the answer, incorporating suggestions in my solution, minus the user non-existent condition.
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string sql = #"
SELECT Employee.Id, Role.Id AS [RoleId], Role.NAME AS [RoleName]
FROM Employee
LEFT OUTER JOIN EmployeeRole on Employee.Id = EmployeeRole.EmployeeId
LEFT OUTER JOIN Role on EmployeeRole.RoleId = Role.Id
WHERE Employee.Id = #Id";
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#Id", SqlDbType.Int).Value = id;
using (SqlDataReader reader = command.ExecuteReader())
{
List<object> roles = new List<object>();
while (reader.Read()) // 404 condition missing?
{
roles.Add(new {Id = reader.GetInt32(1), Name = reader.GetString(2)});
}
return roles;
}
}
}
Query 2
Will it work if we combine both queries? however, I don't know how to retrieve double query result from the reader.
string sql = #"SELECT FIRST FROM Employee WHERE Id = #Id;
SELECT Employee.Id, Employee.First, Role.Id AS [RoleId], Role.NAME AS [RoleName]
FROM Employee
LEFT OUTER JOIN EmployeeRole on Employee.Id = EmployeeRole.EmployeeId
LEFT OUTER JOIN Role on EmployeeRole.RoleId = Role.Id
WHERE Employee.Id = #Id2";
I'd suggest using SQL like:
SELECT Employee.Id, Role.WhateverColumnYouWantHere
FROM Employee LEFT OUTER JOIN Role On Employee.Id = Role.EmployeeID
WHERE Employee.Id = #Id
If the employee isn't there then Read will return false. If the employee is there, but lacks a role, then Role.WhateverColumnYouWantHere will be NULL (IsDBNull will return true).
Additionally, you likely want to remove your for (int i = 0; i < roleIds.Length; i++) loop (leave the logic inside it - just remove the loop) since it isn't doing anything useful. Also, change if (reader.Read()) to while (reader.Read()) to handle the possibility of multiple roles. Plus, you likely should use reader.GetInt32(0) rather than Int32.Parse(reader.GetString((0)) - assuming that the Id is a 32-bit integer (rather than a string). Also, remove the , 32 code - it is unnecessary, since SqlDbType.Int has a fixed size (i.e. it knows it is 32-bits).

Procedure or function 'usp_hotelRoom' expects parameter '#name', which was not supplied

Can somebody help me debug my code?
Basically I have created a stored procedure and I want to call that stored procedure inside my website (ASP.NET).
This code is for my stored procedure:
CREATE PROCEDURE usp_hotelRoom
#country VARCHAR(50),
#name VARCHAR(50)
AS
BEGIN
SELECT
Room.roomID, Room.roomName, Room.type, Room.capacity, Room.roomSize,
Room.description, Room.remarks, Room.services, Room.photo,
Room.price, Hotel.name
FROM
Room
INNER JOIN
Hotel ON Hotel.orgEmail = Room.orgEmail
WHERE
country = #country
AND Hotel.name = #name;
END
EXEC usp_hotelRoom 'singapore', 'marina bay sands';
This code is for calling the stored procedure:
public static List<Room> getHotelRoomByCountry(string country, string name)
{
SqlConnection con = new SqlConnection(conStr);
try
{
SqlCommand command = new SqlCommand();
command.Connection = con;
command.CommandType = System.Data.CommandType.StoredProcedure;
command.CommandText = "usp_hotelRoom";
var paramname = new SqlParameter
{
ParameterName = "#country",
Value = country
};
command.Parameters.Add(paramname);
var paramhotel = new SqlParameter
{
ParameterName = "#hotel.name",
Value = name
};
command.Parameters.Add(paramhotel);
con.Open();
SqlDataReader reader = command.ExecuteReader();
List<Room> rooms = null;
if (reader.HasRows)
rooms = new List<Room>();
while (reader.Read())
{
rooms.Add(
new Room()
{
RoomID = reader["roomID"].ToString(),
RoomName = reader["roomName"].ToString(),
Type = reader["type"].ToString(),
Capacity = reader["capacity"].ToString(),
RoomSize = reader["roomSize"].ToString(),
Desc = reader["description"].ToString(),
Remarks = reader["remarks"].ToString(),
Services = reader["services"].ToString(),
Pictures = reader["photo"].ToString(),
Price = reader["price"].ToString(),
});
}
reader.Close();
return rooms;
}
finally
{
con.Close();
}
}
Hope someone can help me. I would appreciate it on your work!
I try to do it by myself and doesn't work, until I try to add new class attributes inside of the Room class (Hotel.Name)
Thanks!
Change this line of code
ParameterName = "#hotel.name"
to
ParameterName = "#name"

How to properly return count(*) values from scalar valued function

Every time I execute my code I get "false" from method
public bool exists(int vpisna, string geslo)
{
bool a = false;
Uspeh = true;
cmd = new SqlCommand("SELECT dbo.fnExists(#Vpisna,#Geslo)", povezava);
cmd.Parameters.AddWithValue("#Vpisna", vpisna);
cmd.Parameters.AddWithValue("#Geslo", geslo);
try
{
povezava.Open();
int result =(int)cmd.ExecuteScalar();
if (result==1)
{
a = true;
}
}
catch (Exception e)
{
ex = e;
}
finally
{
povezava.Close();
}
return a;
}
My scalar valued function:
[dbo].[fnExists](
#Vpisna int,
#Geslo nvarchar(40)
)
RETURNS INT AS BEGIN
DECLARE #a int
SET #a = (
SELECT
COUNT(*)
FROM
Student
WHERE
ID = #Vpisna
AND
Geslo = CONVERT( nvarchar(40), HashBytes('SHA1', #Geslo ), 2 )
)
RETURN #a
END
Everytime I get a false result, even when I try to manipulate data inside of the scalar valued function. When I try the SELECT statement on real data without a the function it works inside the SQL Management Studio.
I think your code series is wrong. Before create sql command must open sql connection or must open from sqlcommand.
Use this;
SqlConnection cnn = new SqlConnection("sql-connection-string");
cnn.Open();
SqlCommand cmd = new SqlCommand("select 1", cnn);
or
SqlConnection cnn = new SqlConnection("sql-connection-string");
SqlCommand cmd = new SqlCommand("select 1", cnn);
cmd.Connection.Open();
[dbo].[fnExists](
#Vpisna int,
#Geslo nvarchar(40)
)
RETURNS INT AS BEGIN
DECLARE #a int
SELECT
#a = COUNT(*)
FROM
Student
WHERE
ID = #Vpisna
AND
Geslo = CONVERT( nvarchar(40), HashBytes('SHA1', #Geslo ), 2 )
RETURN #a
END

Oracle 12C:Return the record after insert values

I want to get the value to insert a table in C#,something like this:
begin
insert into bk_library(floor,section) values('foo2','bar')
returning id into :outid;
select *from bk_library where id=:outid;
end;
Unfortunately, I failed
error info: Kiss.Linq.Linq2Sql.Test.EntryPoint.TestInsertReturnId:
Oracle.DataAccess.Client.OracleException : ORA-06550: line 3, column
1: PLS-00428: an INTO clause is expected in this SELECT statement
[Test]
public void TestInsertReturnId()
{
int ret = 0;
string connstring = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=pdborcl)));User Id=system;Password=****;";
string sql = #"insert into bk_library(floor,section) values('foo','bar') returning id into :outid";
sql = getSqlString();
using (DbConnection conn = new OracleConnection(connstring))
{
conn.Open();
DbCommand command = conn.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = sql;
OracleParameter lastId = new OracleParameter(":outid", OracleDbType.Int32);
lastId.Direction = ParameterDirection.Output;
command.Parameters.Add(lastId);
ret = command.ExecuteNonQuery();
// this code work fine ,now I want to get the entire record
LogManager.GetLogger<EntryPoint>().Info("The new id ={0}", lastId.Value.ToString());
conn.Close();
}
Assert.AreNotEqual(ret, 0);
}
ParameterDirection should be ReturnValue
lastId.Direction = ParameterDirection.ReturnValue;
From < http://arjudba.blogspot.ch/2008/07/pls-00428-into-clause-is-expected-in.html?m=1>
You need to write SELECT * INTO some_variable FROM bk_library instead of SELECT * FROM bk_library because I assume you want to store the data retrieved somehow. Therefore you need to declare a new variable some_variable (I assume of type string) and modify your SELECT statement as above. The data from the statement will then be stored in your new variable.
Hope this helps

Categories

Resources