How to save a SQL "Select" result in a variable in C# - c#

I'm using Visual C# connected to MySQL for study purposes and I'm stuck in throwing an error to the user when he types a username that already exists.
Current code to put things into the database (it may be useless, once my question may be much more about SQL):
s = new sql(); // This calls a class that works as an adapter to connect form with the database
Conn = s.Connection;
Conn.Open();
coma = Conn.CreateCommand();
coma.CommandText = "INSERT INTO test.test (`user`,`password`) VALUES ('"+username.Text+"','"+password.Text+"');";
coma.ExecuteNonQuery();
What I want to do it compare "username.Text" ("username" is a TextBox) with the values on database's "test" table and, if some value match, evoke a MessageBox.Show("Hey guy, this username is already in use! Try something different)

Some points about your code sample
You want to be sure that you dispose of your connection and command objects. For my answer, I've wrapped them in using statements which will take care of that for me.
You do not want to go to the database with unsanitized inputs. I am going to use parameterized queries in the example.
It's not a good idea to store passwords in plain text. I am not going to demonstrate more secure techniques, just know to look for information about encrypting passwords, salt keys, etc.
And now for some code. In this, I'm using OleDb objects, retrofit to your particular database. And, of course, provide appropriate names to tables, columns, etc.
using (OleDbConnection connection = SomeMethodReturningConnection())
using (OleDbCommand command = SomeMethodReturningCommand())
{
command.Parameters.Add(new OleDbParameter("#username", username));
command.CommandText = "Select Count(*) From Users where Username = #username";
connection.Open();
int output = (int)command.ExecuteScalar();
if (output > 0)
{
// username already exists, provide appropriate action
}
else
{
// perform insert
// note: #username parameter already exists, do not need to add again
command.Parameters.Add(new OleDbParameter("#password", password));
command.CommandText = "Insert Into Users (Username, Password) Values (#username, #password)";
command.ExecuteNonQuery();
}
}

Thank you Anthony! Your answer put me on the right track. Although there is something that the people who will read this post should change from your code in order to get it working with Odbc connectors: the way as parameters are parsed and the way as the textbox content is extracted:
using (OdbcConnection connection = SomeMethodReturningConnection())
using (OdbcCommand command = SomeMethodReturningCommand())
{
command.Parameters.Add(new OdbcParameter("#username", username.Text));
command.CommandText = "Select Count(*) From Users where Username = ?";
connection.Open();
int output = (int)command.ExecuteScalar();
if (output > 0)
{
// username already exists, provide appropriate action
}
else
{
// perform insert
// note: #username parameter already exists, do not need to add again
command.Parameters.Add(new OdbcParameter("#password", password.Text));
command.CommandText = "Insert Into Users (Username, Password) Values (?,?)**";
command.ExecuteNonQuery();
}
}
Thank you anyway!

Related

Error while executing query in C#, SQL Server: trying to update if value already present else insert

I am trying to execute a query with a condition like if username already present then update the row, else insert username and password.
This is my code below:
using (SqlCommand cmd = new SqlCommand("INSERT INTO Users(Username,Password) VALUES(#User,#password) ON DUPLICATE KEY UPDATE Username=VALUES(Username), Password=VALUES(Password)"))
{
cmd.Connection = con;
cmd.Parameters.AddWithValue("#User", TextBox3.Text);
cmd.Parameters.AddWithValue("#password", Pwd);
con.Open();
cmd.ExecuteNonQuery();
}
I got the following error:
Incorrect syntax near the keyword 'ON'.
I am not able to figure out what is wrong in this. Can anyone please help me out?
In SQL Server you need to use a query something like this:
-- check if exists (by username) - if found, update password
IF EXISTS (SELECT * FROM dbo.Users WHERE Username = #User)
UPDATE dbo.Users
SET Password = #password
WHERE Username = #User
ELSE
INSERT INTO dbo.Users(Username, Password)
VALUES(#User, #password)
And as mentioned in my comments - do not use the .AddWithValue function (see linked blog post for details) but use this instead:
cmd.Parameters.Add("#User", SqlDbType.VarChar, 100).Value = TextBox3.Text;
And also, please do not store your passwords in clear text in the database!
It looks like you're using MySQL syntax. I don't think SQL Server has ON DUPLICATE KEY. You'd probably want a MERGE statement.
#marc_s
String query = #"IF EXISTS (SELECT * FROM Users WHERE Username = # User)
UPDATE Users
SET Password = #password
WHERE Username = # User
ELSE
INSERT INTO Users(Username, Password)
VALUES(# User, #password)";
using (SqlCommand cmd = new SqlCommand(query))
I used the code you gave and used to debug points to check if the code is executing ,and it was, still it is not updating or Inserting the values .I cant run the query in SQL server cause each time i open the query window VSudio restarts,i am using trial version of Visual Studio

How to get UUID generated by MySQL into a C# variable

Here is the query:
string query = #"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint)
VALUES (UUID(), #UId, #LogInTime, #MIp, #MFingerPrint);
";
Now I need this last inserted id back, which is a UUID generated by MySQL. As far as I read there is no select_last_insert_id() function for UUIDs!! And I read for php you could assign UUID() function first to a variable and then return that value. But how to go about that in C#?
Something like this, but not exactly:
string query = #"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint)
VALUES (#UUID = SELECT UUID(), #UId, #LogInTime, #MIp, #MFingerPrint);
"; //how to do this here?
Here is more of my code:
string query = #"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint)
VALUES (#UUID = SELECT UUID(), #UId, #LogInTime, #MIp, #MFingerPrint);
";
try
{
if (_conn.State != ConnectionState.Open)
_conn.Open();
MySqlCommand cmd = new MySqlCommand(query, _conn);
cmd.Parameters.AddWithValue("#UId", Utility.usr.Id);
cmd.Parameters.AddWithValue("#LogInTime", DateTime.Now);
cmd.Parameters.AddWithValue("#MIp", GetMachineIP());
cmd.Parameters.AddWithValue("#MFingerPrint", GetHardwareFingerPrint());
var s= Convert.ToString(cmd.ExecuteScalar()); //this returns an empty string :(
//I need to get it to any .NET data type, string, or Guid or byte[] or anything.
But I need this datatype of s to be used in another WHERE clause in a query like this:
string query = #"UPDATE session SET logout_time = #LogOutTime
WHERE user_id = #UId AND PK_Id = #SessionId";
try
{
if (_conn.State != ConnectionState.Open)
_conn.Open();
MySqlCommand cmd = new MySqlCommand(query, _conn);
cmd.Parameters.AddWithValue("#UId", Utility.usr.Id);
cmd.Parameters.AddWithValue("#SessionId", s);
cmd.Parameters.AddWithValue("#LogOutTime", DateTime.Now);
cmd.ExecuteScalar();
Here #"SessionId" is the UUID field in the same table. So basically, how can I get the MySQL varbinary field in C# so that I could use that type to update by specifying WHERE in another query?
In MySQL table the UUID field is varbinary (I hope to see some solution that is not another php link or that is not asking me to switch to char datatype in the database :) ).
Edit: The problem here is we have already added plenty of UUIDs generated by MySQL into the table, so I'm a bit apprehensive about changing MySQL UUID to .NET Guid. If that's the only workaround, I'll consider that. Just that this is the first time we needed the inserted UUID value back so that I can update in another query another point of time.
A sub question: Is .NET Guid exactly the same thing as MySQL UUID?
You can use the Guid type which is the MS implementation of UUID. You should be aware that when inserting data into the DB, you may need to convert the Guid to ByteArray if the MySQL driver isn't familiar with handling Guid's. See Store GUID in MySQL from C# for an example of this.
I think you can go ahead with your earlier implementation without having to rely on MS Guid, but I fear I am too late :)
string query = #"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint)
VALUES (UUID(), #UId, #LogInTime, #MIp, #MFingerPrint);
SELECT PK_Id FROM session WHERE login_time=#LogInTime AND machine_fingerprint=#MFingerPrint; //or something similar which gives you the exact same id - UUID
";
try
{
if (_conn.State != ConnectionState.Open)
_conn.Open();
MySqlCommand cmd = new MySqlCommand(query, _conn);
cmd.Parameters.AddWithValue("#UId", Utility.usr.Id);
cmd.Parameters.AddWithValue("#LogInTime", DateTime.Now);
cmd.Parameters.AddWithValue("#MIp", GetMachineIP());
cmd.Parameters.AddWithValue("#MFingerPrint", GetHardwareFingerPrint());
MySqlDataReader r = cmd.ExecuteReader();
if (r.Read()) //ensure if it is read only once, else modify your `WHERE` clause accordingly
{
var s = (Guid)r[0];
}
//or even (Guid)cmd.ExecuteScalar() would work
Now you can query in update like this:
string query = #"UPDATE session SET logout_time = #LogOutTime
WHERE user_id = #UId AND PK_Id = #SessionId";
try
{
if (_conn.State != ConnectionState.Open)
_conn.Open();
MySqlCommand cmd = new MySqlCommand(query, _conn);
cmd.Parameters.AddWithValue("#UId", Utility.usr.Id);
cmd.Parameters.AddWithValue("#SessionId", s.ToByteArray());
cmd.Parameters.AddWithValue("#LogOutTime", DateTime.Now);
cmd.ExecuteNonQuery();
Note: Here I have converted the Guid variable s to byte array before querying. This is important, in WHERE clause, be it UPDATE or SELECT statements in query. I would ask you to move to binary field in MySQL table from varbinary.
Edit: If your table would grow dramatically large then inserting and selecting is a bad idea since SELECT query is an additional query being run. In that case #PinnyM's choice is better. I really do not think MySQL or any other database would have a default way to give back "custom" inserted ids which are not something database generated. So in short I advice you to not go for this..
Edit2: See this answer for getting binary value to .NET datatype. Sometimes casting do not work depending on MySQL .NET connector version..

Use parametrized sql queries when SQLCommand used in separate class

I am interesting to add parametrize sql queries in my ASP.net application. I have seen some good articles regarding Avoid SQL Injection.
string sql = string.Format("INSERT INTO [UserData] (Username, Password, Role, Membership, DateOfReg) VALUES (#Username, #Password, #Role, #Membership, #DateOfReg)");
SqlCommand cmd = new SqlCommand(sql, conn);
try
{
cmd.Parameters.AddWithValue("Username", usernameTB.Text);
cmd.Parameters.AddWithValue("Password", passwordTB.Text);
cmd.Parameters.AddWithValue("Role", roleTB.Text);
cmd.Parameters.AddWithValue("Membership", membershipTB.Text);
cmd.Parameters.AddWithValue("DateOfReg", dorTB.Text);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
find the Reference
However this way is not useful to me since I couple the DB connection to separate class since I have reuse it.
public class DBconnection{
public int insertQuery(String query) {
int affectedRowCount = 0;
SqlConnection conn = null;
try{
conn = new SqlConnection("Server=localhost;Database=master;UID=sa;PWD=sa;");
SqlCommand cmd = new SqlCommand( query, conn );
cmd.CommandType = CommandType.Text;
conn.Open( );
affectedRowCount = cmd.ExecuteNonQuery( );
conn.Close( );
} catch ( Exception e ){
String error = e.Message;
}
return affectedRowCount;
}
}
Therefore I only use bellow code part to call above class and Insert values to DB.
String SQLQuery1 = insert into Article values('" + Txtname.Text + "','" + TxtNo.Text + "','" + Txtdescription.Text + "' ,0)");
DBconnection dbConn = new DBconnection();
SqlDataReader Dr = dbConn.insertQuery(SQLQuery1);
Please help me to use Parameterize sqlString to Avoid me Sql Injection.
To use #name , # No and #description without use Textbox inputs.
It's perfectly reasonable to do this, but have your class call back (lambda/delegate) out to get the parameters. This is a static method in a class which is called by various overloaded instance methods:
private static int SqlExec(string ConnectionString, string StoredProcName, Action<SqlCommand> AddParameters, Action<SqlCommand> PostExec)
{
int ret;
using (var cn = new SqlConnection(ConnectionString))
using (var cmd = new SqlCommand(StoredProcName, cn))
{
cn.Open();
cmd.CommandType = CommandType.StoredProcedure;
if (AddParameters != null)
{
AddParameters(cmd);
}
ret = cmd.ExecuteNonQuery();
if (PostExec != null)
{
PostExec(cmd);
}
}
return ret;
}
Then, a usage example:
public void Save()
{
Data.Connect().Exec("Project_Update", Cm =>
{
Cm.Parameters.AddWithValue("#ProjectID", ID);
Cm.Parameters.AddWithValue("#PrimaryApplicantID", PrimaryApplicant.IdOrDBNull());
Cm.Parameters.AddWithValue("#SecondaryApplicantID", SecondaryApplicant.IdOrDBNull());
Cm.Parameters.AddWithValue("#ProjectName", ProjectName.ToDBValue());
});
}
It's also possible to do this with non-stored procedure calls.
In your case it would look like:
DBconnection.InsertQuery(
"INSERT INTO [UserData]
(Username, Password, Role, Membership, DateOfReg)
VALUES (#Username, #Password, #Role, #Membership, #DateOfReg)"
,cmd => {
cmd.Parameters.AddWithValue("Username", usernameTB.Text);
cmd.Parameters.AddWithValue("Password", passwordTB.Text);
cmd.Parameters.AddWithValue("Role", roleTB.Text);
cmd.Parameters.AddWithValue("Membership", membershipTB.Text);
cmd.Parameters.AddWithValue("DateOfReg", dorTB.Text);
}
);
Which puts all your database stuff together the way you want and lets the DBconnection keep its internals isolated.
How about instead of a generic InsertQuery() method you write specific InsertQuery methods?
For example:
public void AddNewUser(User u)
{
var query = "insert Users (name, password) values (#0, #1)";
SqlCommand cmd = new SqlCommand(query, conn);
try
{
cmd.Parameters.AddWithValue("#0", u.UserName);
cmd.Parameters.AddWithValue("#1", u.Password);
}
}
This has the advantage of ALL your SQL logic being in this other class, as opposed to the calling class needing to know how to construct the query etc.
It also makes your code more readable, because you see AddUser or UpdateUser or ChangePassword as method calls, and don't have to read SQL at that moment to try and guess what is going on in the program.
HOWEVER if you're going to do something like this, you should check out some MicroORMs, my personal favorite is PetaPoco (or the NuGet version)
PetaPoco and others like Massive and Dapper would let you do something like:
database.Insert(u);
Where u is a User object that maps to your DB's table. It uses ADO.NET and makes sure to use SQL Parameters.
I would suggest using LINQ to SQL, which automatically parametrizes everything.
Q. How is LINQ to SQL protected from SQL-injection attacks?
A. SQL injection has been a significant risk for traditional SQL queries formed by concatenating user input. LINQ to SQL avoids such injection by using SqlParameter in queries. User input is turned into parameter values. This approach prevents malicious commands from being used from customer input.
You can insert, update and delete from a SQL database in a straightforward manner using a DataContext (right-click on your project to add a new item and add the LINQ to SQL Classes template, then use the Server Explorer to add objects to it).
I haven't worked with this in a while, but I believe your code would then look somewhat like this:
UserData user = new UserData();
user.Username = ...;
user.Password = ...;
user.Role = ...;
user.Membership = ...;
user.DateOfReg = ...;
db.UserDatas.InsertOnSubmit(user);
db.SubmitChanges();
When you call SubmitChanges, LINQ to SQL automatically generates and executes the SQL commands that it must have to transmit your changes back to the database.
Edit1:
As an added note, to retrieve an existing item from a database, you could do this:
var user = (from i in db.UserDatas
where i.UserName == "devan"
select i).Single();
Oh, and as is my standard policy when answering questions about databases with login information, I must implore you, for the love of god and all that is holy, to salt and hash your users' passwords.

C# forms Textbox value against database value, sql command or datadapter dataset

Basically what I'm trying to achieve is the following:-
I have a text box field with a value, I want to check this value against the value in the SQL Server database if there's a match then do a particular task.
This is what I have so far:
SELECT userID, username , password
FROM Users
WHERE (username = textboxUsername.text) AND (password = textboxPassword.text
But it doesnt seem to work for me, I think I'm almost doing it correctly?
Also would I be better off using a data set or just a bog stand sql command as there will be other queries to be carried out?
Many thanks
Expanding a little on mazzucci's answer:
using (var con = new SqlConnection("connection string"))
{
con.Open();
var cmd = new SqlCommand(#"SELECT userID, username, password FROM Users WHERE (username = #username) AND (password = #password)");
cmd.Parameters.AddWithValue("#username", textboxUsername.Text);
cmd.Parameters.AddWithValue("#password", textboxPassword.Text);
if (cmd.ExecuteNonQuery() > 0)
{
//They were the same
}
}
However, consider that whatever you're doing looks fairly dangerous. I think Eric Lippert has made more than a few posts on SO about the dangers of passwords and authentication stuff in general.
Such as this one:
Does salt need to be random to secure a password hash?
You need to create the query using the values from the textboxes.
You can do this with named parameters for example to ensure values are escaped properly:
SqlCommand cmd = new SqlCommand();
cmd.CommandText = #"SELECT userID, username , password
FROM Users
WHERE (username = #username) AND (password = #password)";
cmd.Parameters.AddWithValue("#username", textboxUsername.Text);
cmd.Parameters.AddWithValue("#password", textboxPassword.Text);
...

How to insert an integer into a database through command prompt

I am trying to insert a integer into a database in C# using the code below, but everytime I run the compiler informs me that my integer is not a valid column "Invalid Column Name UserID"
Does anyone have any insight on this? Thanks.
Console.WriteLine("Please enter a new User Id");
string line = Console.ReadLine();
int UserID;
if (int.TryParse(line, out UserID))
{
Console.WriteLine(UserID);
Console.ReadLine();
}
//Prepare the command string
string insertString = #"INSERT INTO tb_User(ID,f_Name, l_Name) VALUES (UserID,'Ted','Turner')";
First things first, I would get into the habit of using parameterised queries, if you are not planning to use stored procedures. In your example, I would:
using (var command = new SqlCommand("INSERT INTO tb_User(ID, f_Name, l_Name) VALUES (#id, #forename, #surname)", conn))
{
command.Parameters.AddWithValue("id", id);
command.Parameters.AddWithValue("forename", forename);
command.Parameters.AddWithValue("surname", surname);
command.ExecuteNonQuery();
}
Where id, forename, surname are the appropriate variables. Notice I am also using using blocks, this ensures that my objects are cleaned up after it has completed.
it is because the 'UserID' within your insertString : ..."VALUES (UserID"... is invalid.
you need to pass a value for the UserID such as: ..."VALUES ('myUserIDGoesHere'"...
Your string is not dynamically reading the variables. Use something like this:
string insertString =
string.Format(#"INSERT INTO
tb_User(ID,f_Name, l_Name) VALUES
({0},'{1}','{2}')", UserId, "Ted",
"Turner");
There are better ways depending on what kind of data access you're using, but this is just to make the point of how to correct the string.
The problem is the first argument in VALUES - it simply isn't defined. If this is meant to be the value the user has entered, then you need to add a parameter to the command and use that parameter in the SQL; for example:
cmd.Parameters.AddWithValue("#id", UserID);
An then use
VALUES(#id, ...
in the TSQL.
Also, generally you might want to have the system generate the unique id. A the simplest level this could have an IDENTITY defined (an automatic sequence).
Use a parameterized query:
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using (var insertCommand = new SqlCommand(
#"INSERT INTO tb_User (ID, f_Name, l_Name)
VALUES (#ID, 'Ted', 'Turner')", connection))
{
insertCommand.Parameters.AddWithValue("#ID", userID);
insertCommand.ExecuteNonQuery();
}
}
To answer your question regardless of your approach, try:
string insertString = #"INSERT INTO tb_User(ID,f_Name, l_Name) VALUES ("
+ UserID + ",'Ted','Turner')";

Categories