Convert user-defined function to stored procedure for EF - c#

This is my user-defined function used in a project:
CREATE FUNCTION [dbo].[Encrypt]
(
#Password nvarchar(4000)
)
RETURNS varbinary(4000)
AS
BEGIN
SELECT #Password = CONVERT(nvarchar(4000),#Password);
RETURN HashBytes('SHA1', #Password);
END
GO
I need Entity Framework so, it's possible find a way to convert this one in a stored procedure in SQL Server 2012 Express?

Procedure Definition
CREATE PROCEDURE [dbo].[usp_Encrypt]
#Password nvarchar(4000),
#HashedPass varbinary(4000) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET #HashedPass = HashBytes('SHA1',CONVERT(nvarchar(4000),#Password));
END
EXECUTE PROCEDURE
DECLARE #RtnHashedPass varbinary(4000);
EXECUTE [dbo].[usp_Encrypt]
#Password = 'myPassword'
#HashedPass = #RtnHashedPass OUTPUT
SELECT #RtnHashedPass --<-- Do what ever you want to do with this value

Related

SELECT statement won't return row first time after INSERT commit transaction

I have two stored procedures, one AddReportsApi for inserting data with a BEGIN TRANSACTION and COMMIT TRANSACTION, and the other GetReportsApi for selecting the data for inserted row.
I call the INSERT stored procedure first, then I call the SELECT stored procedure but sometimes it does not return any rows for the passed in SearchItemId which is used in the WHERE predicate.
If I execute the SELECT stored procedure a second time, it returns the expected rows.
Is there a delay in inserting the data to the table? Please note that the stored procedures are called from HangFire background job framework. From my test, HangFire should not affect the INSERT and SELECT stored procedure calls. The INSERT stored procedure is called multiple times within a minute to insert the records into the ReprotsApi table.
Insert stored procedure:
CREATE PROCEDURE [dbo].[AddReportsApi]
#OrderID nvarchar(50),
#SearchItemId nvarchar(50),
#SubjectID nvarchar(50),
#SearchType nvarchar(50),
#ApiName nvarchar(50),
#ApiRequest text,
#ApiResponse text,
#IsActive bit,
#CreatedOn datetime,
#CreatedBy nvarchar(50),
#ModifyOn datetime,
#ModifyBy nvarchar(50),
#HitType nvarchar(2)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION
INSERT INTO [dbo].[ReportsApi] ([OrderID], [SearchItemId], [SubjectID], [SearchType],
[ApiName], [ApiRequest], [ApiResponse], [IsActive],
[CreatedOn], [CreatedBy],
[ModifyOn], [ModifyBy], [HitType])
VALUES (#OrderID, #SearchItemId, #SubjectID, #SearchType,
#ApiName, #ApiRequest, #ApiResponse, #IsActive,
#CreatedOn, #CreatedBy,
#ModifyOn, #ModifyBy, #HitType)
IF (##ERROR != 0)
BEGIN
ROLLBACK TRANSACTION
END
ELSE
COMMIT TRANSACTION
END
SELECT stored procedure:
CREATE PROCEDURE [dbo].[GetReportsApi]
#OrderID nvarchar(50)
,#SearchItemId nvarchar(50)
,#SubjectID nvarchar(50)
,#CreatedBy nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
SELECT [Id]
,[OrderID]
,[SearchItemId]
,[SubjectID]
,[SearchType]
,[ApiName]
,[ApiRequest]
,[ApiResponse]
,[IsActive]
,[CreatedOn]
,[CreatedBy]
,[ModifyOn]
,[ModifyBy]
,[HitType]
FROM [dbo].[ReportsApi] WHERE [SearchItemId] = #SearchItemId
END
it might be because indexes are being rebuilt under the hood after the insert completes.
This can give dirty/phantom reads.
If you have an index on [SearchItemId] then the 2nd query might use this but the index may still being refreshed.
This can even affect clustered indexes if you are inserting into the middle of the B-Tree.
It might be worth sticking a sleep(10000) or WAITFOR DELAY '00:00:10'; into your code...
(That's 10 sec but you could experiment with different timings.)
Good luck!

How do I check that values are being inserted into a table when the result of the insert shows nothing?

I've ran into an issue concerning a SQL Server procedure that is supposed to insert data into three tables. The code below shows that the procedure takes in parameters and then inserts said parameters into three tables: an Address table, a D.O.B table and a Users table.
Ignoring the salt as that has to do with something else, my issue is that when I run this procedure from an ASP.NET MVC file, nothing is inserted into the Users table, even though the Address and D.O.B table both have their respective values inserted into them. I've had an issue like this before which was solved because the problem was that one of the values was returning NULL when I used a HASHBYTES procedure on it, however, here there is nothing that I can think that would be doing something similar.
ALTER PROCEDURE [dbo].[StoreDetails]
#FirstName VARCHAR(50),
#Surname VARCHAR(50),
#Password VARCHAR(100),
#PhoneNumber VARCHAR(50),
#Email VARCHAR(100),
#IsAdmin BIT,
#Address VARCHAR(100),
#DOB DATE
AS
BEGIN
SET NOCOUNT ON
DECLARE #Salt UNIQUEIDENTIFIER = NEWID()
INSERT INTO dbo.OAddress(Address)
VALUES (#Address)
INSERT INTO dbo.ODOB(DOB)
VALUES (#DOB)
INSERT INTO dbo.OUsers (FirstName, Surname, Password, Salt, PhoneNumber, Email, IsAdmin, AddressID, DOBID)
VALUES (#FirstName, #Surname, #Password, #Salt, #PhoneNumber, #Email, #IsAdmin, SCOPE_IDENTITY(), SCOPE_IDENTITY())
END
The C# side of this I believe does work as intended as not too long ago I managed to get this code to work until I changed the stored procedure to try and change the Password parameter to get hashed using HASHBYTES however I decided to just revert back to when it worked normally but as you can see I'm failing.
Seems like what you likely need is a couple of OUTPUT clauses and some table variables:
ALTER PROCEDURE [dbo].[StoreDetails] #FirstName varchar(50),
#Surname varchar(50),
#Password varchar(100),
#PhoneNumber varchar(50),
#Email varchar(100),
#IsAdmin bit,
#Address varchar(100),
#DOB date
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Salt uniqueidentifier = NEWID();
DECLARE #AddressID table (ID int);
DECLARE #DOBID table (ID int);
INSERT INTO dbo.OAddress ([Address])
OUTPUT inserted.ID
INTO #AddressID (ID) --Guessed named for inserted
SELECT #Address;
INSERT INTO dbo.ODOB (DOB)
OUTPUT inserted.ID
INTO #DOBID (ID) --Guessed named for inserted
SELECT #DOB;
INSERT INTO dbo.OUsers (FirstName,
Surname,
Password,
Salt,
PhoneNumber,
Email,
IsAdmin,
AddressID,
DOBID)
SELECT #FirstName,
#Surname,
#Password,
#Salt,
#PhoneNumber,
#Email,
#IsAdmin,
A.ID,
D.ID
FROM #AddressID A
CROSS JOIN #DOBID D;
END;
Note the comments I make on the OUTPUT clauses.
You need to figure out what the database is telling you about the problem.
Put a breakpoint in your code and then grab all the values that the variables contain that you are putting into your parameters. Then switch to SQL, set up all your variables, and try running the statements from the procedure, and get the error message. Something like this:
declare #FirstName VARCHAR(50) = 'John'
declare #Surname VARCHAR(50) = 'Smith'
declare #Password VARCHAR(100) = 'Hek3$s*aSf8'
declare #PhoneNumber VARCHAR(50) = '333-333-3333'
declare #Email VARCHAR(100) = 'john#mailinator.com'
declare #IsAdmin BIT = 0
declare #Address VARCHAR(100) = '100 Somewhere Street, Somewheretown'
declare #DOB date = '2019-10-10'
DECLARE #Salt UNIQUEIDENTIFIER=NEWID()
INSERT INTO dbo.OAddress(Address)
VALUES(#Address)
INSERT INTO dbo.ODOB(DOB)
VALUES(#DOB)
INSERT INTO dbo.OUsers(FirstName,Surname,Password,Salt,PhoneNumber,Email,IsAdmin,AddressID,DOBID)
VALUES(#FirstName,#Surname,#Password,#Salt,#PhoneNumber,#Email,#IsAdmin,SCOPE_IDENTITY(),SCOPE_IDENTITY())
I think we probably need to suspect the SCOPE_IDENTITY() function calls, but there's only one way to find out: run it and see.
The problem here is the use of SCOPE_IDENTITY(). This returns the last identity value generated by the insert statement. In your code, SCOPE_IDENTITY() is returning the value inserted for dbo.oDOB.
In order for this to work, you would need to capture the value for SCOPE_IDENTITY() into a local variable after each of the insert statements, then use those values in your final insert into dbo.oUsers.
The following should get you what you want:
ALTER PROCEDURE [dbo].[StoreDetails]
#FirstName VARCHAR(50),
#Surname VARCHAR(50),
#Password VARCHAR(100),
#PhoneNumber VARCHAR(50),
#Email VARCHAR(100),
#IsAdmin BIT,
#Address VARCHAR(100),
#DOB DATE
AS
BEGIN
SET NOCOUNT ON
DECLARE #addressKey INT,
#dobKey INT;
DECLARE #Salt UNIQUEIDENTIFIER = NEWID();
INSERT INTO dbo.OAddress(Address)
VALUES (#Address);
SET #addressKey = SCOPE_IDENTITY();
INSERT INTO dbo.ODOB(DOB)
VALUES (#DOB);
SET #dobKey = SCOPE_IDENTITY();
INSERT INTO dbo.OUsers (FirstName, Surname, Password, Salt, PhoneNumber, Email, IsAdmin, AddressID, DOBID)
VALUES (#FirstName, #Surname, #Password, #Salt, #PhoneNumber, #Email, #IsAdmin, #addressKey, #dobKey)
END
Firstly, you should run stored procedure with the params to know what are error messages exactly.
Secondly, You should handle error message inner stored procedure and check after each time you inserted.
For example:
INSERT INTO dbo.OAddress(Address)
VALUES(#Address)
IF ##ERROR <> 0
BEGIN
PRINT N'A check constraint violation occurred.';
Return;
END
GO
However, You should also use out put param then RETURN ##ERROR to check in c# whether it's inserted successfully or not

Entity Framework doesn't properly execute stored procedure that returns a boolean

I'm using Microsoft SQL Server 2014 and I have a stored procedure in my database called spLogin that returns a boolean to indicate whether or not login was successful.
This is the stored procedure:
USE [MyDataBase]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spLogin]
#loginName NVARCHAR(50),
#password NVARCHAR(50)
AS
BEGIN
SET NOCOUNT ON
DECLARE #bit BIT
IF NOT EXISTS (SELECT TOP 1 User.UserID FROM User WHERE User.LoginName=#loginName)
OR RTRIM(LTRIM(#loginName)) IS NULL OR RTRIM(LTRIM(#loginName)) IS NULL
SET #bit=0
ELSE
BEGIN
DECLARE #userID INT
SET #userID= (SELECT User.UserID FROM User WHERE User.LoginName=#loginName
AND User.Password=HASHBYTES('SHA2_512', #password+CAST(User.Salt AS NVARCHAR(36))))
IF(#userID IS NULL)
SET #bit = 0
ELSE
SET #bit = 1
END
RETURN #bit
END
When I execute this stored procedure on Microsoft SQL Server 2014 Management Studio, it returns 1 if I pass the correct arguments. For example:
USE [MyDataBase]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[spLogin]
#loginName= N'adminCharles',
#password= N'admin123'
SELECT 'Return Value' = #return_value
GO
In this case, it returns the value I expected, which is 1.
But, when I use Entity Framework on a WPF project, it returns -1 even though I'm passing the correct arguments. For instance:
DataBaseEntities context = new DataBaseEntities();
var login = context.spLogin("adminCharles","admin123");
//output: -1
In that case, it outputs -1 and I just simply don't know why.
I would really appreciate some help here. Thanks in advance.
And by the way, this is just a simple project for learnign Entity Framework.
EDIT
I changed #bit BIT for INT and at the end of the stored procedure, I wrote this:
SET #bit=0
RETURN #bit
I updated my project and I'm still getting -1. Could it be a permissions issue?

How to return a statements in stored procedure

This is my procedure :
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[uspChangeMemberRole]
#TeamID INT,
#MemberID INT,
#MemberRole TINYINT
AS
BEGIN
SET NOCOUNT ON;
UPDATE [dbo].[TeamMember]
SET MemberRole = #MemberRole
WHERE TeamID = #TeamID
AND MemberID = #MemberID;
RETURN #MemberRole;
END
When I execute this procedure I want to return "MemberRole Successfully Changed".
Please give me a solution how to return
Use Row Count to check if there are affected rows (identified if update is successful) then select a string.
RowCount - Returns the number of rows affected by the last statement.
IF ##ROWCOUNT > 0
BEGIN
SELECT 'Member Role Successfully Chnaged';
END
And I think this statement is not necessary since this is an input parameter, you can get outside the proc.
return #MemberRole;
Change your return to select, and replace the datatype of your output parameter with varchar.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[uspChangeMemberRole]
#TeamID INT,
#MemberID INT,
#MemberRole VARCHAR(100) OUTPUT
AS BEGIN
SET NOCOUNT ON;
UPDATE [dbo].[TeamMember] SET MemberRole=#MemberRole WHERE TeamID=#TeamID AND MemberID=#MemberID;
SET #MemberRole = 'MemberRole Successfully Changed.'
SELECT #MemberRole AS 'RETURN';
I am adding some of the concept that will help you to understand how Procedure's will return values.
If you want to return something from SQL Server to Frontend, Just use "select" statement.
You have to use proper command from frontend like you want to return scalar value, or query.

Row count of a stored procedure from another stored procedure

I have various stored procedures. I need a stored procedure to execute a stored procedure and then return only the row count (number of returned rows by the called procedure) and I need to receive it in c# code.
What's the best way to do this?
Assuming you are using SQL Server (which is possible from the code snippets), perhaps something like this would work for you:
exec('exec <your stored procedure goes here>; select ##RowCount')
Since you are running SQL Server, I can think of one solution that is not necessarily pretty.
Create a temporary table (table variable if you have a more recent version of SQL Server). Then execute:
exec(`
declare #t table (
<columns go here>
);
insert into #t
exec(''<your exec here>'');
select #rowcount
');
And now that I've said that, I would recommend sp_executesql. This goes something like this:
declare #sql nvarchar(max) = N'exec '+#YOURQUERY + '; set #RowCount = ##RowCount';
exec sp_executesql #sql, N'#RowCount int output', #RowCount = RowCount output;
I spent most of yesterday debugging an arcane condition that arises when you call a stored procedure inside an insert.
You can try this in your child stored procedure :
CREATE PROC PawanXX
(
#a INT
,#b INT OUTPUT
)
AS
BEGIN
SELECT TOP 2 * FROM X
SET #b = ##ROWCOUNT
RETURN #b
END
GO
The main stored procedure where we call all other sps
DECLARE #RC int
DECLARE #a int
DECLARE #b int
EXECUTE #RC = [dbo].[PawanXX]
#a
,#b OUTPUT
SELECT #RC
The output for the same
ProcessName Parent Child
ShareDrafts Job12 Job03
ShareDrafts Job13 Job58
(2 row(s) affected)
2
(1 row(s) affected)

Categories