Verify SQL has executed correctly in WebMatrix/Razor? - c#

I am trying to verify if my SQL has been executed correctly, and if not return an error.
My code :
var db = Database.Open("database");
db.Execute("INSERT INTO Users(Username, Email, FirstName, SecondName) VALUES(?,?,?,?)", username, email, firstName, secondName);
Also, how can you mark a column as unique using WebMatrix? This seems to be a pretty basic functionality that I am really missing! I want to make it so that emails and usernames must be unique, but I cannot see any way to do this? I am essentially then hoping to test if the INSERT INTO can be executed (i.e there is no email/username the same already existing in the database).
Thank you for the help.

For your first question:
The Execute method returns the number of affected records, and your code snip is doing an insert so if it fails it'll return a value that isn't equal to 1.
var db = Database.Open("database");
if (db.Execute("INSERT INTO Users(Username, Email, FirstName, SecondName) VALUES(?,?,?,?)", username, email, firstName, secondName) < 1)
throw new Exception("Wasn't able to insert User record");
The second, I'm not sure about but it should probably be asked in a separate question.

I would create a stored procedure that conditionally adds the new user and returns a row count (0 if the user already exists):
create procedure dbo.AddUser
#username varchar(80)
, #email varchar(128)
, #firstname varchar(128)
, #secondname varchar(128)
as
insert into [Users] (Username,Email,FirstName,SecondName)
select #username, #email, #firstname, #secondname
where not exists(
select 1 from [Users] (nolock)
where Username=#username
and Email=#email
)
return ##rowcount
go
Calling from C#:
var db = Database.Open("database");
if (db.Execute("dbo.AddUser #username=?, #email=?, #firstname=?, #secondname=?", username, email, firstName, secondName) < 1)
throw new Exception("Wasn't able to insert User record");

Related

Stored procedure called from form returns duplicate row error, but the record does not exist in table, what's going on?

I am getting the following error when calling a stored procedure from a Windows Form's button click.
Cannot insert duplicate key row in object 'dbo.User' with unique index 'IX_User_Username'. The duplicate key value is (someusername).
However, my table is empty, so there shouldn't be a duplicate key row error.
The stored procedure does work correctly if I execute it directly from Visual Studio by right-clicking the Stored Procedure and then Execute, I then type in the values and it executes correctly.
I am using
Visual Studio Community Edition 2019
SQL Server Express
.NET 4.7.03190
Here is the User object - this model takes in user's first and last names, username, passwords and handles password hashing and salts.
The Create() method inserts calls the stored procedure.
public User(String firstName, String lastName, string username, string password)
{
this.firstName = firstName;
this.lastName = lastName;
this.username = username;
Password newPassword = new Password(password);
newPassword.Hash();
this.password = newPassword.GetHashedPassword();
this.salt = newPassword.GetSalt();
this.loginAttempts = 0;
this.locked = false;
}
public void Create()
{
database = new Database();
using (SqlConnection conn = database.GetSqlConnection())
{
using (SqlCommand command = new SqlCommand("CreateUserStoredProcedure", conn))
{
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.AddWithValue("#firstName", this.firstName);
command.Parameters.AddWithValue("#lastName", this.lastName);
command.Parameters.AddWithValue("#username", this.username);
command.Parameters.AddWithValue("#password", this.password);
command.Parameters.AddWithValue("#salt", this.salt);
command.Parameters.AddWithValue("#loginAttempts", this.loginAttempts);
command.Parameters.AddWithValue("#locked", this.locked);
conn.Open();
command.ExecuteNonQuery();
using (SqlDataReader reader = command.ExecuteReader())
{
while(reader.Read())
{
// returns the result for testing
Console.WriteLine("From Reader - ");
Console.WriteLine(reader["Return Value"]);
}
}
}
}
}
And here's the stored procedure:
CREATE PROCEDURE [dbo].[CreateUserStoredProcedure]
#firstName NVARCHAR(50),
#lastName NVARCHAR(50),
#username NVARCHAR(50),
#password NVARCHAR(36),
#salt NVARCHAR(255),
#loginAttempts INT = 0,
#locked BIT = 0
AS
BEGIN
DECLARE #Id INT
INSERT INTO [dbo].[Users]
VALUES (#username)
SET #Id = (SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY])
INSERT INTO [dbo].[People] (User_Id, FirstName, LastName)
VALUES (#Id, #firstName, #lastName)
INSERT INTO [dbo].[Credentials] (User_Id, "Password", Salt, LoginAttempts, Locked)
VALUES (#Id, #password, #salt, #loginAttempts, #locked)
RETURN 1
END
Table structure is simple:
User (Id, Username) (Unique Index 'IX_User_Username')
People (User_Id, FirstName, LastName) (FK User_Id > User.Id)
Credentials (User_Id, Password, Salt, LoginAttempts, Locked) (FK User_Id > User.ID)
I am expecting the new user to be added from the form, from given input data, just as it does when executing the stored procedure directly.
I have tested in the Create() method by using Console.WriteLine() for each input data to make sure that I am sending the correct values to the stored procedure. Surely, the username is getting sent correctly:
Can you help me to determine the issue? Thanks.
EDIT:
Stored Procedure
CREATE PROCEDURE [dbo].[CreateUserStoredProcedure]
#firstName nvarchar(50),
#lastName nvarchar(50),
#username nvarchar(50),
#password nvarchar(36),
#salt nvarchar(255),
#loginAttempts int = 0,
#locked bit = 0
AS
BEGIN TRY
BEGIN TRANSACTION
DECLARE
#Id int
INSERT INTO [dbo].[User]
VALUES
(#username)
SET #Id = (SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY])
--SET #Id = (SELECT Id FROM [dbo].[User] WHERE Username = #username)
INSERT INTO [dbo].[Person]
(User_Id, FirstName, LastName)
VALUES
(#Id, #firstName, #lastName)
INSERT INTO [dbo].[Credential]
(User_Id, "Password", Salt, LoginAttempts, Locked)
VALUES
(#Id, #password, #salt, #loginAttempts, #locked)
RETURN 1
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF(##TRANCOUNT > 0)
ROLLBACK TRANSACTION
RAISERROR ('User could not be created', 0, 0);
END CATCH

Getting an update syntax error from a SqlDataSource in asp.net

I keep getting a syntax error when trying to run an update query in a SqlDataSource in asp.net.
UPDATE User
SET userName = #userName,
password = #password,
UserType = #UserType,
datejoined = #datejoined,
email = #email,
loggedIn = #loggedIn,
picFilePath = #picFilePath
WHERE
userName = #userName
All the tables are saved in a MS Access 2010 file and all the parameters are saved in session, but I don't think it's relevant since this is just a syntax error.
Any help would be appreciated.
User and password are MS Access reserved words, I'd suggest using square brackets for the table name and all of the column names:
UPDATE [User]
SET [userName] = #userName,
[password] = #password,
[UserType] = #UserType,
[datejoined] = #datejoined,
[email] = #email,
[loggedIn] = #loggedIn,
[picFilePath] = #picFilePath
WHERE
[userName] = #userName
Is there really a space in here?
loggedIn = # loggedIn
^
|
+---> should there be a space here?
I don't think there should be a space between the # and the loggedIn
In addition: in SQL Server, User is a reserved keyword - so in SQL Server, you need to use [User] for your table name instead. Not sure if that applies to MS Access, too.

How to return the value of Identity element

I have a table in SQL Server with 3 columns Id (int identity), email (nvarchar(50)), password (nvarchar(50)). Now I want to write a query where I can insert email and password and that time, I want to return the identity element for id.
For e.g I insert abc#dal.ca and password then the identity element value should be returned.
I wrote it as:
#email nvarchar(50), #password nvarchar(50), #id int
insert into addEmail(email, password)
values(#email,#password)
return #id
Is this proper ?? How should I do ? How should I check whether this is working properly or not ? If I select
dbo.sp_addEmailReturnId abc#dal.ca, demo
and click on execute, it shows
Incorrect syntax near '.'.
I am unable to find the error. I am just trying to insert email id and password so that could be inserted and i would get the identity element which is automatically incremented by 1 with every new row.
In code part for asp.net, how would I retrieve the id. ?
try
insert into addEmail(email,password)
OUTPUT INSERTED.ID
values(#email,#password)
Try this query; it will fetch you the id
insert into addEmail(email, password) values(#email,#password) Select ##IDENTITY;
Do like this
private int getEmail(string email, string password)
{
string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
using (SqlConnection conn = new SqlConnection(cs))
{
conn.Open();
SqlCommand cmd = new SqlCommand("sp_addEmailReturnid", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#email", email);
cmd.Parameters.AddWithValue("#password",password);
int nUploadId = Convert.ToInt32(cmd1.ExecuteScalar()); } // Updated Part
NOTE
At the end of your stored proc i.e after insert statement add
Select Scope_Identity()
Edit
Your proc would be sometihng like this
ALTER proc [dbo].[sp_addEmailReturnid]
#email VARCHAR(500),
#password VARCHAR(500)
AS
BEGIN
// Your insert statement here
Select Scope_Identity()
End
Use Scope_Identity
insert into addEmail(email,password) values(#email,#password)
SELECT SCOPE_IDENTITY()

How to write update stored procedure in webmatrix form?

Here I write update query in my webmatrix form which run correctly but I want to use a stored procedure in place of query so how can I write that?
var UpdateQuery = "UPDATE Reg_tb SET FirstName = #0, LastName = #1, UserName = #2, Password = #3 WHERE UID = #4";
db.Execute(UpdateQuery, FirstName, LastName, UserName, Password, Userid);
Maybe this?
var execProc="EXEC ProcName FirstName=#0,LastName=#1,UserName=#2,Password=#3, UID=#4";
db.Execute(execProc,FirstName,LastName,UserName,Password,Userid);

SELECT inside INSERT query?

I am trying to insert the user id from table users inside table session , field session_user, using textbox , but it seems it doesn't work ..
Here is my SQL code, I am using visual studio and trying to insert to a SQL Server table
SqlCommand addsession = new SqlCommand
("insert into dbo.session(session_user)
values (select user_id from dbo.users where username = '" + TextBox1.Text + "')",
badersql);
You shouldn't use the VALUES keyword when you're doing an INSERT ... SELECT:
insert into dbo.session (session_user) select user_id from dbo.users ...
If you are inserting the result of a query into another table, just leave out the VALUES keyword.
The VALUES keyword can always be replaced by a simple SELECT 'dummy', 'value' of the values you want to insert, but I suggest you still use VALUES whenever you want to make it clear that your results do not come from a query.
That being said, please use parameterized queries!! Imagine if someone were to enter the following text into TextBox1:
' or 1 = 1
What would happen?
To insert records from a query use this insert syntax:
insert into dbo.session (session_user)
select user_id from dbo.users where username = '" + TextBox1.Text + "'
You may want to do a select top 1 userid if you are expecting one row to be inserted like in the values statement.
i did it , the problem was that i can not name my record session_user , so i replaced with se_user and that solve the problem .
thank u all for ur help
so the correct sql statement is
insert into sessions (se_user) select USER_ID from users where username = '';

Categories