Can't call stored procedure - c#

I'm a beginner at C#. I can't call a stored procedure.
My stored procedure is this:
CREATE PROCEDURE USP_login
#us VARCHAR(20),
#pwd VARCHAR(20)
AS
BEGIN TRAN
BEGIN TRY
SELECT *
FROM dbo.KhachHang
WHERE tenDangNhap = #us AND matKhau = #pwd
END TRY
BEGIN CATCH
ROLLBACK TRAN
RETURN 0
END CATCH
COMMIT TRAN
RETURN 1
GO
In my C# code, I use this function to call the USP_login stored procedure but it doesn't work:
public bool loginStored(string us, string pwd)
{
object[] sqlParams =
{
new SqlParameter ("#userName", us),
new SqlParameter ("#passWord", pwd),
};
var rs = db.Database.SqlQuery<bool>("USP_login #userName, #passWord", sqlParams).SingleOrDefault();
return rs;
}
Error message in screenshot:

Looks like SELECT * ... is returning more than just a single bool. (Based on the query, clearly the table has at least two fields, tenDangNhap and matKhau.) But that's what you told the code to expect:
db.Database.SqlQuery<bool>(/.../)
Either select only the column you want:
SELECT SomeBooleanValue FROM dbo.KhachHang WHERE tenDangNhap=#us AND matKhau=#pwd
Or specify the correct type that can be expected for each record (which may be a custom class that you need to define):
db.Database.SqlQuery<SomeObjectType>(/.../)

Related

C# Web API using Dapper to insert data using a stored procedure - unable to get inserted record Id

I'm new to Dapper - please help me. How can I get the inserted record value after a successful insert?
Stored procedure:
ALTER PROCEDURE Sp_InsertTestData
#Name varchar(50),
#gender int,
#refres int OUTPUT
AS
BEGIN
INSERT INTO Test_Master (Name, Gender)
VALUES (#Name, #gender);
SELECT #refres = SCOPE_IDENTITY()
SELECT #refres as M_SID
END
When I execute this stored procedure in SQL like this:
DECLARE #refres INT
EXEC Sp_InsertTestData 'test12',1,#refres
I'm getting an output showing the last inserted row's value.
But when this stored procedure is executed from C# code, every time I'm getting a value of 1:
using (SqlConnection con = new SqlConnection(_configuration.GetConnectionString("DatabaseConnection")))
{
con.Open();
SqlTransaction sqltrans = con.BeginTransaction();
var param = new DynamicParameters();
param.Add("#Name", Bindtestmaster.Name);
param.Add("#gender", Bindtestmaster.Gender);
param.Add("#refres");
res = con.Execute("Sp_InsertTestData", param, sqltrans, 0, CommandType.StoredProcedure);
}
That's because you are getting the result of the stored procedure call, which tells you the number of rows inserted (which is 1).
You want to read the output parameter #refres (and add it to your DynamicParameters as an output parameter)
/* ... */
param.Add("#refres", dbType: DbType.Int32, direction: ParameterDirection.Output);
con.Execute("Sp_InsertTestData", param, sqltrans,0,CommandType.StoredProcedure);
var yourId = param.Get<int>("#refres");
Btw, on your stored procedure instead of:
select #refres=SCOPE_IDENTITY()
You might want to prefer this:
SET #refres = SCOPE_IDENTITY() AS INT
And I'm not sure what that last SELECT is there for
Or directly output the inserted ID (using the OUTPUT SQL clause on the INSERT) and then you could read the result, and not have an output parameter at all.
Since your stored procedure also selects the output:
select #refres as M_SID
An easier way of doing this might be:
var id = con.ExecuteScalar<int>("Sp_InsertTestData", new {
Name = Bindtestmaster.Name,
gender = Bindtestmaster.Gender
}, sqltrans, 0, CommandType.StoredProcedure);
and forget DynamicParameters etc. You could also consider using the OUTPUT clause in the SQL, to simplify it:
ALTER PROCEDURE Sp_InsertTestData
#Name varchar(50), #gender int
AS
BEGIN
INSERT INTO Test_Master(Name, Gender)
OUTPUT INSERTED.Id -- whatever the column is here
VALUES (#Name, #gender);
END

How to Get IDENT_CURRENT result with c# ' s SqlCommand?

I have a stored procedure in which I want to get the last inserted row for a specific table say table TbUsers , so in the end of it, I type that line:
select IDENT_CURRENT('TbUsers')
Now I want to get that result in C#, using SqlCommand; I pass these parameters to to the stored procedure:
SqlCommand command = new SqlCommand("InsertUsers", conn);
command.CommandType = System.Data.CommandType.StoredProcedure;
/* Insert in TbUsager */
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter("#firstName" ,value.firstname),
new SqlParameter("#lastName",value.lastname),
new SqlParameter("#email",value.email),
new SqlParameter("#phoneNumber",value.phoneNumber),
new SqlParameter("#address",value.address),
new SqlParameter("#country",value.country),
new SqlParameter("#city",value.city),
new SqlParameter("#zipCode",value.zip_code)
};
command.Parameters.AddRange(parameters);
var rdr = command.ExecuteReader()
How can I get the returned result of the stored procedure?
Update
i have added this code :
// command.Parameters.AddRange(parameters);
var LastInsertedUsagerId = new SqlParameter("#lastInsertedUsagerId", System.Data.SqlDbType.Int);
LastInsertedUsagerId.Direction = ParameterDirection.Output;
command.Parameters.Add(LastInsertedUsagerId);
// var rdr = command.ExecuteReader();
var LastInsertedUsagerId2 = command.Parameters["#LastInsertedUsagerId"].Value;
but i still getting null as a result ?
Update2
this is my SP:
ALTER PROCEDURE [dbo].[InsertUsager]
-- Add the parameters for the stored procedure here
#Nom_Usager varchar(20),
#Prenom_Usager varchar(20),
#Email_Usager varchar(20),
#Telephone_Portable_Usager varchar(20),
#Adresse_Usager varchar(20),
#Pays_Usager varchar(20),
#Ville_Usager varchar(20),
#IdVille_Usager varchar(20),
#LastInserted_IdUsager int OUTPUT
AS
BEGIN
-- Insert a new usager
declare #IdinsertedUsager table(IdinsertedUsager int)
declare #IdAddressVillePayselse table(IdAddressVillePayselse int)
declare #newUsager int , #IdAddressVillePays int , #addressvp int,#IdCountry int,#IdVille int
Insert into TbUsager (IdTypeUsager,Nom_Usager,Prenom_Usager,Indic_Maj)
Output inserted.IdUsager into #IdinsertedUsager
values(1,#Prenom_Usager,#Nom_Usager,'P')
SELECT #newUsager = IdinsertedUsager FROM #IdinsertedUsager
/* some code */
select #LastInserted_IdUsager=IDENT_CURRENT('TbUsers')
END
and it works well when i execute it in sqlserver
Assuming you're returning the identity id correctly(as output parameter) in your SP, in your C# code you can retrieve it like this:
var id = command.Parameters["#id"].Value;
Change #id to the name of your output variable in SP.
Here's a link to see how to do it correctly in detail:
https://www.aspsnippets.com/Articles/Return-Identity-value-from-Stored-Procedure-in-SQL-Server.aspx
Solved, in addition to #Siavash is answer , in order to work we need to use : command.ExecuteNonQuery()
instead of command.ExecuteReader()
In this documentation we get the difference and when to use each one.

One function for multiple stored procedures C#

I have a function that executes stored procedures. The thing is, I wish to use this one function for multiple stored procedures that take different arguments.
Of course, if I do so, I will get an error saying that
Procedure or function has too many arguments specified
What I want to do is to create the function such that when it executes a stored procedure, that stored procedure only takes the parameters that it needs and ignore the others. Is this possible?
Here is what I have so far:
try
{
using (SqlConnection con = new SqlConnection(consr))
{
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
cmd.CommandText = stp;
cmd.Parameters.Add(new SqlParameter("#proc1", cmb1.SelectedItem.ToString()));
cmd.Parameters.Add(new SqlParameter("#proc2", cmb2.SelectedItem.ToString()));
cmd.Parameters.Add(new SqlParameter("#proc3", cmb3.SelectedItem.ToString()));
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
con.Open();
reader = cmd.ExecuteReader();
con.Close();
}
}
catch (SqlException exp)
{
throw new InvalidOperationException(exp.Message);
}
Here are two of the procedures:
ALTER PROCEDURE [dbo].[test1]
#proc1 varchar(20)
AS
Begin
select * from tab where name=#proc1
END
and
ALTER PROCEDURE [dbo].[test1]
#proc2 varchar(20)
AS
Begin
select * from tab where name=#proc2
END
I want to use the same function to execute both
You can set the params you don't want to use to null, then check for which values are available and respond accordingly
ALTER PROCEDURE [dbo].[test1]
#proc1 varchar(20) = null
#proc2 varchar(20) = null
#proc3 varchar(20) = null
AS
Begin
IF #proc1 IS NOT NULL BEGIN
select * from tab where name=#proc1
END
END
Make your function take two arguments, the name of the SP and a 2d array of SP argument names and their corresponding values. Then set up your sql command by iterating over the 2d array and adding the parameters in the loop.
If you need to return several result sets, see here: How do I return multiple result sets with SqlCommand? and modify the function and args so that they take an array of SP names and an array of 2d arrays, containing the SP arg names and values for each SP.
I think you should use this structure :
CREATE PROCEDURE MyProcName
#Parameter1 INT = 1,
#Parameter2 VARCHAR (100) = 'StringValue',
#Parameter3 VARCHAR (100) = NULL
AS
/* check for the NULL / default value (indicating nothing was passed */
if (#Parameter3 IS NULL)
BEGIN
/* whatever code you desire for a missing parameter*/
INSERT INTO ........
END
/* and use it in the query as so*/
SELECT *
FROM Table
WHERE Column = #Parameter
Can you please share the stored procedure code? I think you need to use if else or case statement in your function and call appropriate stored procedure with required parameters inside your function.

Stored procedure not running correctly with dynamic sql text

For some reason my stored procedure is executed without any error from the code-behind in C# but it is not deleting anything at all that the stored procedure has written. I have all the correct parameters and everything. I ran the query from SQL Server with all the same parameters from the C# code and it works perfectly. I don't get why it works when I run from SQL Server but it doesn't work when I run it from my C# code in Visual Studio.
Here is my C# code that is passing the data through to the stored procedure.
string reportType = "PostClaim";
string GRNBRs = "925','926','927";
string PUNBRs = "100','100','100";
string beginningDates = "20120401";
string endDates= "20120430";
try
{
conn = new SqlConnection(ConnectionInfo);
conn.Open();
SqlDataAdapter da = new SqlDataAdapter("RemoveReport", conn);
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.SelectCommand.Parameters.AddWithValue("#ReportType", reportType);
da.SelectCommand.Parameters.AddWithValue("#GRNBR", GRNBRs);
da.SelectCommand.Parameters.AddWithValue("#PUNBR", PUNBRs);
da.SelectCommand.Parameters.AddWithValue("#DATE1", beginningDates);
da.SelectCommand.Parameters.AddWithValue("#DATE2", endDates);
da.SelectCommand.CommandTimeout = 360;
}
catch (SqlException ex)
{
//something went wrong
throw ex;
}
finally
{
if (conn.State == ConnectionState.Open)
conn.Close();
}
Here is my stored procedure. It's executing with dynamic SQL text.
ALTER PROCEDURE [dbo].[RemoveReport] (
#ReportType NVARCHAR(20),
#GRNBR VARCHAR(4000),
#PUNBR VARCHAR(4000),
#DATE1 DATETIME,
#DATE2 DATETIME
)
AS
DECLARE #SQLTEXT VARCHAR(4000)
BEGIN
SET #SQLTEXT = 'DELETE FROM TestingTable
WHERE Report='''+#ReportType+''' AND
PUNBR IN ('''+#PUNBR+''') AND
[Group] IN ('''+#GRNBR+''') AND
StartedAt BETWEEN '''+CONVERT(VARCHAR(10),#DATE1,121)+'''
AND '''+CONVERT(VARCHAR(10),#DATE2,121)+''''
PRINT #SQLTEXT <---I'll print this out to show you what exactly it is executing.
EXECUTE (#SQLTEXT)
END
Here is what the PRINT #SQLTEXT is running:
DELETE FROM MonthlyReportSchedule
WHERE Report='PostClaim' AND
PUNBR IN ('100','100','100') AND
[Group] IN ('925','926','927') AND
StartedAt BETWEEN '2012-04-01' AND '2012-04-30'
When I actually go into SQL Server to run this query, it works perfectly. But why does it not work on when executed from the C# code. Any help?
Avoid concatenating parameters to your sql, use parameterised query,
Try this...
Just noticed that you have some comma delimited lists in params.....
ALTER PROCEDURE [dbo].[RemoveReport]
#ReportType NVARCHAR(20),
#GRNBR VARCHAR(4000),
#PUNBR VARCHAR(4000),
#DATE1 DATETIME,
#DATE2 DATETIME
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQLTEXT NVARCHAR(MAX);
Declare #GRNBR_xml xml,#PUNBR_xml xml;
SET #GRNBR_xml = N'<root><r>' + replace(#GRNBR, ',','</r><r>') + '</r></root>';
SET #PUNBR_xml = N'<root><r>' + replace(#PUNBR, ',','</r><r>') + '</r></root>';
SET #SQLTEXT = N'DELETE FROM TestingTable
WHERE Report = #ReportType
AND PUNBR IN (select r.value(''.'',''varchar(max)'') as item
from #PUNBR_xml.nodes(''//root/r'') as records(r))
AND [Group] IN (select r.value(''.'',''varchar(max)'') as item
from #GRNBR_xml.nodes(''//root/r'') as records(r))
AND StartedAt BETWEEN #DATE1 AND #DATE2'
EXECUTE sp_executesql #SQLTEXT
,N'#ReportType NVARCHAR(20) , #GRNBR_xml xml,
#PUNBR_xml xml,#DATE1 DATETIME,#DATE2 DATETIME'
,#ReportType
,#GRNBR_xml
,#PUNBR_xml
,#DATE1
,#DATE2
END
Note
Make sure you pass the comma delimited list as 925,926,927 and not as '925','926','927'
Try adding this line in order to be executed
da.SelectCommand.ExecuteNonQuery();
This will execute a call to your stored procedure.
good luck

Issue in reading stored procedure parameter value

I am unable to read value from stored procedure when executing it.
Here is my stored procedure
ALTER Procedure [dbo].[SaveInvitation]
(
#InvitationID INT OUTPUT,
#UserID INT,
#Email NCHAR(100),
#InvitationGUID UNIQUEIDENTIFIER OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
IF #UserID = -1
BEGIN
SET #UserID = NULL
END
IF NOT EXISTS (SELECT 1 FROM Invitations WHERE LTRIM(RTRIM(Email)) = LTRIM(RTRIM(#Email)))
BEGIN
INSERT INTO Invitations (UserID,
Email,
CreateDate)
VALUES (#UserID,
#Email,
GETDATE())
-- GET NEWLY INSERTED INVITATIONS ID
SET #InvitationID = IDENT_CURRENT('Invitations')
-- GET GUID FROM INVITATION ID
SELECT #InvitationGUID = InvitationGUID
FROM Invitations
WHERE InvitationID = #InvitationID
END
ELSE
BEGIN
RAISERROR('ALREADY_INVITATED', 16, 127)
END
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK
END
EXEC ThrowError
END CATCH
END
I am executing this procedure from this function
My DataBaseModel.Designer.cs:
public ObjectResult<SaveInvitation_Result> SaveInvitation(ObjectParameter invitationID, Nullable<global::System.Int32> userID, global::System.String email, ObjectParameter invitationGUID)
{
ObjectParameter userIDParameter;
if (userID.HasValue)
{
userIDParameter = new ObjectParameter("UserID", userID);
}
else
{
userIDParameter = new ObjectParameter("UserID", typeof(global::System.Int32));
}
ObjectParameter emailParameter;
if (email != null)
{
emailParameter = new ObjectParameter("Email", email);
}
else
{
emailParameter = new ObjectParameter("Email", typeof(global::System.String));
}
return base.ExecuteFunction<SaveInvitation_Result>("SaveInvitation", invitationID, userIDParameter, emailParameter, invitationGUID);
}
It throws an exception
The data reader is incompatible with the specified 'TestModel.SaveInvitation_Result'. A member of the type, 'InvitationGUID', does not have a corresponding column in the data reader with the same name.
I have created a complex type i.e. SaveUserRegistration_Result and imported one function SaveInvitation of return type SaveUserRegistration_Result.
How can I solve above exception? Is there any change in stored procedure?
Screen shot
It's giving you this error because you're not actually SELECTing back a result. If you added a line to the end of your procedure for example:
SELECT #InvitationGUID AS InvitationGUID
It should work just fine for you.

Categories