Editing data into SQL with C# - c#

I have this method for Editing data but I don't know how to write the code... Until now I have this which I don't really understand and I have an error in it. It says incorrect syntax near '('.
public void EditMember(Member member)
{
string Name = member.Name;
string Surname = member.Surname;
string EntryDate = member.EntryDate.ToString("dd.MM.yyyy");
string Status = member.Status;
sqlConnection.Open();
sqlCommand = new SqlCommand(
"UPDATE Members SET (Name, Surname, EntryDate) VALUES('" + Name + "','" + Surname + "','" + EntryDate + "')' WHERE'(' Id '='" + member.Id + "')",
sqlConnection);
sqlCommand.ExecuteNonQuery();
sqlConnection.Close();
}
The problem is when I start to write WHERE
Help please.

Please read all of this answer, not just the first part
There are multiple issues here. The most immediate problem is here:
"')' WHERE'('
That's acting as if you're trying to quote the bracket. That "should" be:
"') WHERE ('
At that point it would look like a valid (but bad) INSERT command... but your use of VALUES which doesn't look like it's a valid way of updating in T-SQL anyway.
However, you shouldn't use this approach at all. It's error-prone, hard to read, and most importantly prone to SQL injection attacks.
Instead, you should use parameterized SQL:
string sql = #"UPDATE Members
SET Name = #Name, Surname = #Surname, EntryDate = #EntryDate
WHERE Id = #Id";
using (var connection = new SqlConnection(...))
{
connection.Open();
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#Name", SqlDbType.NVarChar).Value = member.Name;
command.Parameters.Add("#Surname", SqlDbType.NVarChar).Value = member.Surname;
command.Parameters.Add("#EntryDate", SqlDbType.DateTime).Value = member.EntryDate;
command.Parameters.Add("#Id", SqlDbType.NVarChar).Value = member.Id;
int rows = command.ExecuteNonQuery();
// TODO: Work out what to do if rows isn't 1
}
}
(With adjustments for the appropriate data types, of course.)

You should NEVER EVER concatenate together your SQL statements with user input.
Instead : use parametrized queries - they're easy to use, avoid SQL injection, and improve performance.
Try code something like this:
string updateStmt = "UPDATE dbo.Members SET Name = #Name, Surname = #Surname, EntryDate = #EntryDate WHERE Id = #ID";
sqlCommand = new SqlCommand(updateStmt, sqlConnection);
sqlCommand.Parameters.Add("#Name", SqlDbType.VarChar, 100).Value = name;
sqlCommand.Parameters.Add("#Surname", SqlDbType.VarChar, 100).Value = surname;
sqlCommand.Parameters.Add("#EntryDate", SqlDbType.DateTime).Value = entrydate;
sqlCommand.Parameters.Add("#ID", SqlDbType.Int).Value = member.Id;
sqlConnection.Open();
sqlCommand.ExecuteNonQuery();
sqlConnection.Close();

The correct syntax for an update statement is
"UPDATE Members SET Name = #name, Surname = #surname, EntryDate = #date WHERE id=#id"
Said that, you should use parameterized query like this
public void EditMember(Member member)
{
string Name = member.Name;
string Surname = member.Surname;
string EntryDate = member.EntryDate.ToString("dd.MM.yyyy");
string Status = member.Status;
sqlConnection.Open();
sqlCommand = new SqlCommand("UPDATE Members SET Name = #name, Surname = #surname, " +
"EntryDate = #date " +
"WHERE Id = #id", sqlConnection);
sqlCommand.Parameters.AddWithValue("#name", Name);
sqlCommand.Parameters.AddWithValue("#surname", Surname);
sqlCommand.Parameters.AddWithValue("#date", EntryDate);
sqlCommand.Parameters.AddWithValue("#id", Status);
sqlCommand.ExecuteNonQuery();
sqlConnection.Close();
As a side note, keep in mind that AddWithValue is a simple way to add parameters to you query, but if the perfomance of this query is critical it is better to use a fully defined parameter with the datatype that matches exactly your database column's type and with the exact size.

Remove the quotes from around the WHERE and you should be fine. Please heed the warnings given in the comments about SQL injection attacks.

Your code has syntax error for update and also SQLInjection issue.
You need to pass parameters to update query rather than passing direct values.
It should be as follows:
public void EditMember(Member member)
{
string Name = member.Name;
string Surname = member.Surname;
string EntryDate = member.EntryDate.ToString("dd.MM.yyyy");
string Status = member.Status;
sqlConnection.Open();
sqlCommand = new SqlCommand("UPDATE Members SET Name=#Name, Surname=#Sirname, EntryDate=#EntryDate WHERE Id = #id", sqlConnection);
sqlCommand.parameters.AddparameterWithValue("#Name",Name);
sqlCommand.parameters.AddparameterWithValue("#Surname",Surname);
sqlCommand.parameters.AddparameterWithValue("#EntryDate",EntryDate);
sqlCommand.parameters.AddparameterWithValue("#Id",Id);
sqlCommand.ExecuteNonQuery();
sqlConnection.Close();
}

Edit the post to make correct answer:
i.e. you don't need brackets in where clause. And yes the better query is
"UPDATE Members SET Name=#Name, Surname=#Surname, EntryDate=#EntryDate WHERE Id=#ID"
and then you add #Name, #Surname, .. etc through parameter of command object.

Related

sqlreader reading wrong column

Im trying to get the unique id from my persons table but the reader keeps trying getting the FirstName column and trying to convert that instead. at least thats what i think is happening
dataAdapter.SelectCommand = new SqlCommand("SELECT ID FROM Persons WHERE FirstName = " + txtBoxFirst.Text.ToString() + " AND LastName = " + txtBoxLast.Text.ToString()
, sqlConnection);
sqlConnection.Open();
SqlDataReader read = dataAdapter.SelectCommand.ExecuteReader();
while (read.Read())
{
pID = (Int32.Parse(read["ID"].ToString()));
}
read.Close();
sqlConnection.Close();
The error shows as
System.Data.SqlClient.SqlException:'Conversion failed when converting the varchar value 'First' to data type int.'
First, you miss the ' single-quote in your query so your parameter willn't be a string.
so it might be like
"SELECT ID FROM Persons WHERE FirstName = '" + txtBoxFirst.Text.ToString() + "' AND LastName = '" + txtBoxLast.Text.ToString() + "'"
But There is a big issue than it is SQL-Injection.
I would suggest you use parameters instead of connected SQL statement string.
make sure your parameter data type size as same as your table schema.
string sqlQuery = "SELECT ID FROM Persons WHERE FirstName = #FirstName AND LastName = #LastName";
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(sqlQuery, connection))
{
command.Parameters.Add("#FirstName", SqlDbType.VarChar,100).Value = txtBoxFirst.Text;
command.Parameters.Add("#LastName", SqlDbType.VarChar, 100).Value = txtBoxLast.Text;
SqlDataReader read = dataAdapter.SelectCommand.ExecuteReader();
while (read.Read())
{
pID = (Int32.Parse(read["ID"].ToString()));
}
}

How do I execute a SqlDataReader after sqlInsertCmd.ExecuteNonQuery

I am inserting a data row into my SQL Server database and then I want to query the data to get the unique identifier from the inserted row but my SqlDataReader is returning an empty dataset. I am thinking it maybe that the transaction hasn't been committed or something like that but I am not sure. I do not get an error.
Here is my code:
try
{
strQuery = "INSERT INTO clientnames VALUES(NEWID(),'" + txtACLastName.Text + "','" + txtACFirstName.Text + "'," + 1 + ")";
using (SqlCommand sqlInsertCmd = new SqlCommand(strQuery, sqlConn))
{
intQueryResult = sqlInsertCmd.ExecuteNonQuery();
if (intQueryResult == 0)
{
blnSuccess = false;
goto InsertClientNamesError;
}
else
{
blnSuccess = true;
}
sqlInsertCmd.Dispose();
}
if (blnSuccess)
{
strQuery = "select clientID from clientnames where firstname = '" + txtACFirstName.Text + "' and lastname = '" + txtACLastName.Text + "'";
using (SqlCommand sqlSelectCmd = new SqlCommand(strQuery, sqlConn))
{
SqlDataReader sqlDataRead = sqlSelectCmd.ExecuteReader();
while (sqlDataRead.Read())
{
strClientID = sqlDataRead.ToString();
}
sqlDataRead.Close();
sqlSelectCmd.Dispose();
}
}
}
catch (Exception exQuery)
{
System.Windows.MessageBox.Show("InsertClientNames: Error, " + exQuery.Message + ", has occurred.");
}
You are not getting the desired result because perhaps the SqlConnection is not opened explicitly (just a guess hard to tell without having full code). But this link shows you how to read from reader --> https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx
But I suggest that you Please do not do it this way. Reason is you are making Two round trips to the DB Server when only one would have done the job for you IF you were using stored procedures. Also you are exposing yourselves to SQL Injection attacks as you are not parameterizing your queries.
Stored procedure:
CREATE PROCEDURE dbo.INS_clientnames
(
#FirstName varchar(100),
#LastName varchar(100),
#NewID int out
)
AS
BEGIN
Declare #Err int
set #NewID = NewID() -- Get the New ID and store it in the variable ( #NewID ) that the SP will return back to the caller
INSERT INTO clientnames values (#NewID , #FirstName , #LastName)
SET #Err = ##ERROR
IF #Error <> 0 -- Check If there was an error
Begin
SET #NewID = -1 -- Indicates that there was an error. You could log this into a Log Table with further details like error id and name.
END
RETURN
END
C# code to execute the above stored procedure and get the NewID:
using(SqlConnection conn = new SqlConnection(connectionString ))
{
using(SqlCommand cmd = new SqlCommand("dbo.INS_clientnames", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters that the Stored Procedure expects
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar, 100);
cmd.Parameters.Add("#LastName" , SqlDbType.VarChar, 100);
cmd.Parameters.Add("#NewId" , SqlDbType.Int).Direction = ParameterDirection.Output;
// set parameter values that your code will send to the SP as parameter values
cmd.Parameters["#FirstName"].Value = txtACFirstName.Text ;
cmd.Parameters["#LastName"].Value = txtACLastName.Text ;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from #NewId
int NewID = Convert.ToInt32(cmd.Parameters["#NewId"].Value);
}
}
Add the following line to your stored procedure that inserts the record
SELECT SCOPE_IDENTITY()
This will return the last identity value inserted in that table.
And use cmd.ExecuteScalar() instead of ExecuteNonQuery()
ExecuteScalar() executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored. [More info][1]
I see two approaches to do this:
either you generate the new GUID on the client side in your C# code and pass it into the query - then you already know what the new id is going to be, so you don't need to do a second query to get it:
you create your GUID on the server side and return it to the caller using the OUTPUT clause in your query
Approach #1:
// define connection string and query
string connStr = "--your connection string here--";
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) VALUES(#ID, #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// create the GUID in C# - this is the ID - no need to go get it again - this *IS* the id
Guid id = Guid.NewGuid();
// set the parameters
cmd.Parameters.Add("#ID", SqlDbType.UniqueIdentifier).Value = id;
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Peter";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Miller";
// open connection, execute query, close connection
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
Approach #2:
// define connection string and query
string connStr = "--your connection string here--";
// query has an "OUTPUT" clause to return a newly inserted piece of data
// back to the caller, just as if a SELECT had been issued
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) OUTPUT Inserted.ClientID VALUES(NEWID(), #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// set the parameters - note: you do *NOT* send in a GUID value - the NEWID() will create one automatically, on the server
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Frank";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Brown";
// open connection
conn.Open();
// execute query and get back one row, one column - the value in the "OUTPUT" clause
object output = cmd.ExecuteScalar();
Guid newId;
if (Guid.TryParse(output.ToString(), out newId))
{
//
}
conn.Close();
}

Getting value from a database using textbox

string que = "SELECT Name FROM StudentInfo where StudentNo=textBox1.Text ";
Every time I run this it always says that
"The multi-part identifier "textBox1.Text" could not be bound".
How do I fix this?
You need to make the query include the value from the textbox. SQL Server doesn't know anything about your textbox - you've just provided the text textBox1.Text as if it refers to something that SQL Server knows about. However, you shouldn't include the value from your textbox in the SQL itself...
Instead, you should parameterize your SQL, and set the parameter from your textbox as a value to be sent alongside the SQL when you execute the query:
// Assuming an open connection...
int studentNo = int.Parse(textBox1.Text);
string sql = "SELECT Name FROM StudentInfo where StudentNo=#student_no";
using (var command = new SqlCommand(conn, sql))
{
command.Parameters.Add("#student_no", SqlDbType.Int).Value = studentNo;
// Execute the command as normal
}
This assumes that the type of StudentNo in your database is Int, of course - adjust accordingly (along with what you do with textBox1.Text - I'm currently parsing it as an int).
You should always parameterize your SQL rather than trying include the value within the SQL itself, for three important reasons:
It protects against SQL Injection Attacks
It avoids unnecessary conversions, and gives you more control over the conversions you do need
It typically makes it easier to read the SQL (as there isn't string concatenation code etc involved) so you can find issues with that more simply
You should be parameterizing your query:
string que = "SELECT Name FROM StudentInfo WHERE StudentNo = #StudentNo"
using (SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["connection"].ConnectionString))
{
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#StudentNo", SqlDbType.VarChar, 50).Value = textBox1.Text;
//If StudentNo is Int
//command.Parameters.Add("#StudentNo", SqlDbType.Int).Value = (int) textBox1.Text;
connection.Open();
string veri = Convert.ToString(command.ExecuteScalar());
return veri;
}
}
Use this :
string strQuery = "SELECT Name FROM StudentInfo where StudentNo= #studentno";
SqlCommand cmd = new SqlCommand(strQuery);
cmd.Parameters.AddWithValue("#studentno", textBox1.Text.Trim());
I really dont understand your question but the query should be
string que = "SELECT Name FROM StudentInfo where StudentNo= '" + textBox1.Text + "';";
If the StudentNo is Varchar in the DB. or else
string que = "SELECT Name FROM StudentInfo where StudentNo=" + textBox1.Text + ";";
Where as you should go for parameterized query like this
using (SqlCommand command = new SqlCommand(
"SELECT Name FROM StudentInfo where StudentNo=#No", connection))
{
command.Parameters.Add(new SqlParameter("No", textBox1.Text));
SqlDataReader reader = command.ExecuteReader();
}

Paramaterized Query With SQL Data Reader C#

I know that non parameterized queries are frowned upon because of SQL injection. Well, I have a lot of queries in my application that are susceptible to SQL injection. I just can't seem to wrap my head around doing it with SqlDataReader. I am able to do it with ExecuteNonQuery just not SQLDataReader.
Can someone give me some pointers and or examples of the best way to do this, the query is executing and returning exactly what it should, I just want to make it as secure as possible....
Code:
string myQuery = "Select [shoeSize] AS 'Shoe Size', [shoeBrand] AS 'Shoe Brand' FROM [myTable] "
+ "WHERE [customerName] = '" + customer + "' AND " + "[customerPin] = '" + customerID + "'";
sqlCmd = new SqlCommand(myQuery, conn);
sqlCmd.Connection.Open();
SqlDataReader rdr2 = sqlCmd.ExecuteReader();
if (rdr2.HasRows)
{
rdr2.Read();
shoeSize= rdr2["Shoe Size"].ToString();
shoeBrand= rdr2["Shoe Brand"].ToString();
}
conn.close();
There you go
string myQuery = "Select [shoeSize] AS 'Shoe Size', [shoeBrand] AS 'Shoe Brand' FROM [myTable] "
+ "WHERE [customerName] = #customerName AND [customerPin] = #customerID"
sqlCmd = new SqlCommand(myQuery, conn);
sqlCmd.Connection.Open();
sqlCmd.Parameters.AddWithValue("#customerName", customerName);
sqlCmd.Parameters.AddWithValue("#customerID", customerID");
--rest stays the same as before
Whereas #customerName and #customerID are now your parameters. So even if the customer's name should be something like "Bigler, Fabian' DROP TABLE [myTable]" it will not work. It completely removes the possibility of "evil" input changing the meaning of your query.
Non-parameterized queries are not simply 'frowned upon'. It can be disastrous for you, your company and - of course - your customer.
Like this:
string myQuery = "Select [shoeSize] AS 'Shoe Size', [shoeBrand] AS 'Shoe Brand' FROM [myTable] "
+ "WHERE [customerName] = #customerName AND [customerPin] = #customerPin";
sqlCmd = new SqlCommand(myQuery, conn);
sqlCmd.Connection.Open();
sqlCmd.Parameters.Add("#customerName", SqlDbType.NVarChar, 50).Value = customer;
sqlCmd.Parameters.Add("#customerPin", SqlDbType.NVarChar, 20).Value = customerID;
SqlDataReader rdr2 = sqlCmd.ExecuteReader();
if (rdr2.HasRows)
{
rdr2.Read();
shoeSize = rdr2["Shoe Size"].ToString();
shoeBrand = rdr2["Shoe Brand"].ToString();
}
conn.close();

Using parameters inserting data into access database

I have the following method to inserting data into an an access databasewhich works fine but I do get a problem if I try to insert text that contains single quotes I have learned.
[WebMethod]
public void bookRatedAdd(string title, int rating, string review, string ISBN, string userName)
{
OleDbConnection conn;
conn = new OleDbConnection(#"Provider=Microsoft.Jet.OleDb.4.0;
Data Source=" + Server.MapPath("App_Data\\BookRateInitial.mdb"));
conn.Open();
OleDbCommand cmd = conn.CreateCommand();
cmd.CommandText = #"INSERT INTO bookRated([title], [rating], [review], [frnISBN], [frnUserName])VALUES('" + title + "', '" + rating + "','" + review + "','" + ISBN + "', '" + userName + "')";
cmd.ExecuteNonQuery();
conn.Close();
}
From what I understand one of the ways to solve the problem is by using parameters. I am not sure how to do this to be honest. How could I change the above code so that I insert the data by using parameters instead?
Same as for any other query:
a) Replace actual hardcoded parameters in your OleDbCommand with placeholders (prefixed with #),
b) Add instances of OleDbParameter to the DbCommand.Parameters property. Parameter names must match placeholder names.
[WebMethod]
public void bookRatedAdd(string title, int rating, string review, string ISBN, string userName)
{
using (OleDbConnection conn = new OleDbConnection(
"Provider=Microsoft.Jet.OleDb.4.0;"+
"Data Source="+Server.MapPath("App_Data\\BookRateInitial.mdb"));
{
conn.Open();
// DbCommand also implements IDisposable
using (OleDbCommand cmd = conn.CreateCommand())
{
// create command with placeholders
cmd.CommandText =
"INSERT INTO bookRated "+
"([title], [rating], [review], [frnISBN], [frnUserName]) "+
"VALUES(#title, #rating, #review, #isbn, #username)";
// add named parameters
cmd.Parameters.AddRange(new OleDbParameter[]
{
new OleDbParameter("#title", title),
new OleDbParameter("#rating", rating),
...
});
// execute
cmd.ExecuteNonQuery();
}
}
}
You have to use Parameter to insert Values. Its is allso a security Issue.
If you do it like that a sql injection could by made.
Try like this:
string ConnString = Utils.GetConnString();
string SqlString = "Insert Into Contacts (FirstName, LastName) Values (?,?)";
using (OleDbConnection conn = new OleDbConnection(ConnString))
{
using (OleDbCommand cmd = new OleDbCommand(SqlString, conn))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("FirstName", txtFirstName.Text);
cmd.Parameters.AddWithValue("LastName", txtLastName.Text);
conn.Open();
cmd.ExecuteNonQuery();
}
}
For Microsoft Access the parameters are positional based and not named, you should use ? as the placeholder symbol although the code would work if you used name parameters provided they are in the same order.
See the documentation for OleDbCommand.Parameters Property
Remarks
The OLE DB .NET Provider does not support named parameters for passing parameters to an SQL statement or a stored procedure called by an OleDbCommand when CommandType is set to Text. In this case, the question mark (?) placeholder must be used. For example:
SELECT * FROM Customers WHERE CustomerID = ?
Therefore, the order in which OleDbParameter objects are added to the OleDbParameterCollection must directly correspond to the position of the question mark placeholder for the parameter in the command text.
Be sure to include the expected schema type where the parameter will be used AND the schema length if applicable.
I also recommend you always use using statements around your instances where the type implements IDisposable like the OleDbConnection so that the connection is always closed even if an exception is thrown in the code.
Changed Code:
var connectionStringHere = #"Provider=Microsoft.Jet.OleDb.4.0;Data Source=" + Server.MapPath("App_Data\\BookRateInitial.mdb";
using (var conn = new OleDbConnection(connectionStringHere))
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "INSERT INTO bookRated ([title], [rating], [review], [frnISBN], [frnUserName]) VALUES(?, ?, ?, ?, ?)";
cmd.Parameters.Add(new OleDbParameter("?", OleDbType.VarChar, 100) { Value = title});
cmd.Parameters.Add(new OleDbParameter("?", OleDbType.Integer) { Value = rating });
cmd.Parameters.Add(new OleDbParameter("?", OleDbType.VarChar, 2000) { Value = review });
cmd.Parameters.Add(new OleDbParameter("?", OleDbType.VarChar, 60) { Value = ISBN });
cmd.Parameters.Add(new OleDbParameter("?", OleDbType.VarChar, 256) { Value = userName });
conn.Open();
var numberOfRowsInserted = cmd.ExecuteNonQuery();
}

Categories