Writing to a database in asp.net - c#

I'm currently finishing an asp.net project for a class and began to notice a major flaw with one of the requisites. The application should ask five questions and write the answers to a database, afterwards it should display the results of the survey to the user.
This is what I have attempted so far:
public static string GetConnectionString()
{
string connStr = String.Format("server={0}; user id={1}; password={2};" + "database= -table to be accessed-; pooling=false",
"-database server-", "-user-", "-password-");
return connStr;
}
protected void Button1_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
string sex = gender.Text;
string likes = interests.Text;
string edu = education.Text;
string nation = nationality.Text;
string userage = age.Text;
MySql.Data.MySqlClient.MySqlConnection mycon;
mycon = new MySqlConnection(GetConnectionString());
try
{
MySqlCommand cmd = new MySqlCommand("INSERT INTO survey (gender, age, birthplace, occupation, winner) VALUES ('" + sex + ", " + likes + ", " + edu + ", " + userage + "')", mycon);
cmd.ExecuteNonQuery();
mycon.Open();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
finally
{
mycon.Close();
}
}
}
I went ahead and replaced the database information with placeholders.
The database is MySql and hosted on an external server.
The issue I'm experiencing is that the code compiles, however the information does not get written to the database. I'm not certain if this is due to the fact that I'm still testing the code and have not uploaded the web application to the server or the fact that it's just wrong.
As far as displaying the results go, if the above code is correct it would simply be a matter of changing the sql query, correct?
Thanks in advance for the insight.

You are executing the command before opening database connection.
ExecuteNonQuery() method and all other Execute method require an open database connection.
And another error is:
Number of columns (i.e. 5) and provided values (i.e. 4) are not equal.
And one more issue in your code is here as stated by Steve Wellens.
Change Your Code like below:
try
{
MySqlCommand cmd = new MySqlCommand("INSERT INTO survey (gender, age, birthplace, occupation, winner) VALUES ('" + sex + ", " + likes + ", " + edu + ", " + userage + "')", mycon);
mycon.Open();
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
finally
{
mycon.Close();
}
Security Notes:
Never add data into query using + operator. It may cause SQL Injection.
What if a user enters 1); DROP TABLE <table-name> -- in Age TextBox..??
Anyone can delete any table entirely from database.
Use MySQL Parameter to avoid such problems. It may prevent from causing serious damages to your entire database.

In your connection string:
"database= -table to be accessed-;
...you don't put the table. The table is specified in the SQL statement.

you should open the connect first, then execute the query.
try
{
MySqlCommand cmd = new MySqlCommand("INSERT INTO survey (gender, age, birthplace, occupation, winner) VALUES ('" + sex + ", " + likes + ", " + edu + ", " + userage + "')", mycon);
mycon.Open();
cmd.ExecuteNonQuery();
}

This is likely not the only problem, but it is a problem:
"INSERT INTO survey (gender, age, birthplace, occupation, winner) " +
"VALUES ('" + sex + ", " + likes + ", " + edu + ", " + userage + "')",
(I've broken it into two strings to make it easier to read.)
You are inserting into five columns. You are only specifying four data values, and with the exception of gender they don't appear to be in the right order or even be the right data.

try checking these things :
try opening your connection before executing the SQL
check your SQL, and try execute them directly against the database. what i see in your SQL is you are concatenating the values into one string (quotes exist only in beginning and end, but not in between the parameters passed)

Related

Exception Unhandled - MySql.Data.MySqlClient.MySqlException

I was gonna save my date and time record in my database when an unhandled exception always thrown at this code: int value = cmd.ExecuteNonQuery(); when I'm clicking the 'Time In' button.
it says that MySql.Data.MySqlClient.MySqlException 'You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'Mar 2022 3:53:00 AM,System.Windows.Forms.DateTimePicker, Value
When I check my codes, there's no errors. I debugged it but no errors appeared.
Here's my codes:
private void btnTimeIn_Click(object sender, EventArgs e)
{
string connectstring = "datasource=localhost;port=3306;username=root;password=;database=employeedb;SslMode=none";
MySqlConnection conn = new MySqlConnection(connectstring);
conn.Open();
string iQuery = "INSERT INTO `attendancerecord`(`EmployeeID`, `EmplLastName`, `EmplFirstName`, `RecordDate`, `TimeIn`, `TimeOut`) VALUES (" + txtEmployeeID.Text + "," + txtLstName.Text + "," + txtFirstName.Text + "," + dateTimePicker1.Value + "," + dateTimePicker2 + "," + dateTimePicker3 + ")";
MySqlCommand cmd = new MySqlCommand(iQuery, conn);
int value = cmd.ExecuteNonQuery();
MessageBox.Show(value.ToString());
conn.Close();
}
Your immediate help, tips and advice are highly appreciated
I was gonna expect that I'm gonna save records in my database by timing in... but I can't even find what could be wrong because i just did all ways of inserting data into table in database. Still, I didn't also work, and the exception still throwing every time at the 'cmd.ExecuteNonQuery' line.
This line of code is causing the bug, and can also lead to SQL injection:
string iQuery = "INSERT INTO `attendancerecord`(`EmployeeID`, `EmplLastName`, `EmplFirstName`, `RecordDate`, `TimeIn`, `TimeOut`) VALUES (" + txtEmployeeID.Text + "," + txtLstName.Text + "," + txtFirstName.Text + "," + dateTimePicker1.Value + "," + dateTimePicker2 + "," + dateTimePicker3 + ")";
You should always use command parameters, not string concatenation:
using (MySqlConnection conn = new MySqlConnection(connectstring))
{
conn.Open();
string iQuery = #"
INSERT INTO `attendancerecord`(`EmployeeID`, `EmplLastName`, `EmplFirstName`,
`RecordDate`, `TimeIn`, `TimeOut`)
VALUES (#id, #last, #first, #date, #in, #out);";
using MySqlCommand cmd = new MySqlCommand(iQuery, conn))
{
cmd.Parameters.AddWithValue("#id", txtEmployeeID.Text);
cmd.Parameters.AddWithValue("#first", txtLstName.Text);
cmd.Parameters.AddWithValue("#last", txtFirstName.Text);
cmd.Parameters.AddWithValue("#date", dateTimePicker1.Value);
cmd.Parameters.AddWithValue("#in", dateTimePicker2.Value);
cmd.Parameters.AddWithValue("#out", dateTimePicker3.Value);
int value = cmd.ExecuteNonQuery();
}
}
Additionally, use using statements to automatically close and clean up database resources.

C# & SQL - Followed examples to write a Parallel.ForEach loop to create threads, but it is throwing exceptions about the connection state

I have tried the code below and it throws exceptions saying that the query requires an open connection, and that the current state is open/opening/closed.
It is a Parallel.ForEach loop creating threads, and I want them to open the connection to the SQL Server database and insert something there. I followed the patterns to handle parallelism in other questions here, but they don't work for me.
Can someone throw some light on this this? How to make this happen?
Connection open error?
Connection closed error
private static void CreateResultTable()
{
Parallel.ForEach(_fakeTableFileFull, tableRow =>
{
var fileRow = Regex.Split(tableRow, PatternExFile);
SearchForConfirm(fileRow[3], fileRow[1], fileRow[2]);
});
}
private static void SearchForConfirm(string id, string number, string date)
{
if (tokenChecksum.ContainsKey(id))
{
WriteLineToResultFile(number, date, tokenChecksum[id], id);
}
}
private static void WriteLineToResultFile(string number, string date, string confirm, string id)
{
using (Conn = new SqlConnection(ConfigurationManager.ConnectionStrings["Database"]
.ConnectionString))
{
Conn.Open();
SqlCommand cmd = new SqlCommand("INSERT INTO [dbo].[PanChecksums] " +
"([number], " +
"[Id]) " +
"VALUES " +
"(" + Int64.Parse(id) +
"," + "'" + confirm + "'" + ")", Conn);
cmd.ExecuteNonQuery();
}
using (Conn = new SqlConnection(ConfigurationManager.ConnectionStrings["Database"]
.ConnectionString))
{
Conn.Open();
SqlCommand cmd = new SqlCommand("SET IDENTITY_INSERT IdNumber ON;", Conn);
cmd.ExecuteNonQuery();
cmd = new SqlCommand("INSERT INTO [dbo].[IdNumber] " +
"([Id], " +
"[number], " +
"[Month], " +
"[Year]) " +
"VALUES " +
"(" + "'" + id + "'" + "," +
Int64.Parse(number) + "," +
"'" + date.Substring(0, 2) + "'" + "," +
"'" + date.Substring(2, 2) + "'" + ")", Conn);
cmd.ExecuteNonQuery();
cmd = new SqlCommand("SET IDENTITY_INSERT IdNumber ON;", Conn);
cmd.ExecuteNonQuery();
}
Instead of:
Parallel.ForEach(list, x=> {...});
Use light weight tasks from ThreadPool:
var tasks = list.Select(x=> Task.Run(()=> {...})).ToArray();
Task.WaitAll(tasks);
Parallel.ForEach is used for heavy CPU load, not for IO load (which is cause of your error, you simply exhaust SQL connection pool). Another approach is to set DegreeOfParallelism:
Parallel.ForEach(list, new ParallelOptions(){ MaxDegreeOfParallelism = 4 }, x => {...});
It will limit connection creation to 4 at the time, but I don't recomend it because you will need manualy manage ALL of your Parallel.ForEach invokations, which can become quite a pain.
Also, your connection is opened twice in row, in one iteration, which is strange. Simply open one connection and use it across all iterations. It will require from you to pass this dependency in every function which need connection, but it is common practice.
Your connections should be open:
Conn.Open();
only close it when the Parralel.ForEach is done.
A better solution wouldbe to merge multiple insert together into 1 insert:
INSERT INTO table (column1, column2)
VALUES
('',''), -- first insert row
('','') -- second insert row
Just join multiple inserts together with a comma.

Error connecting to MS Access database from C# Winform

I'm a student programmer and I'm writing this software for a small school, it's my first program, the code below is giving me the error
syntax error in insert into statement
I know the connection string is not the problem because I use it for inserting into two other tables with the same insert into format.
I am using an access database.
The offending code is
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
command.CommandText = "insert into studentBillRecords (StudentName, Department, Level, AccomodationStatus, SemesterBill, PreviousBalance, TotalBill) values ('"+ txtSRstudentName.Text + "', '" + cmbSRDepartment.Text + "', '" + cmbSRLevel.Text + "', '" + cmbSRAccomodationStatus.Text + "', '" + txtSRSemesterBill.Text + "', '" + txtSRPreviousBalance.Text + "', '" + txtSRTotalBill.Text + "')";
MessageBox.Show(command.CommandText);
command.ExecuteNonQuery();
connection.Close();
This same code with different table names, column names and input works with another table in the same database but won't work with this one.
Level is a reserved keyword in access.
Also use Parameters instead of concatinating string. Try this code out, it makes it safer and easier to read:
Note: I changed the name of the column Level to StudentLevel which, I assume, doesn't exist yet in your table.
try
{
using (OleDbConnection connection = new OleDbConnection("my connection string"))
{
//Open connection
connection.Open();
//Create new command
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = connection;
//Create command text
cmd.CommandText =
"INSERT INTO studentBillRecords " +
"(StudentName, Department, StudentLevel, AccomodationStatus, SemesterBill, PreviousBalance, TotalBill) VALUES " +
"(#StudentName, #Department, #StudentLevel, #AccomodationStatus, #SemesterBill, #PreviousBalance, #TotalBill)";
// Add names paremeters
cmd.Parameters.AddRange(new OleDbParameter[]
{
new OleDbParameter("#StudentName", txtSRstudentName.Text),
new OleDbParameter("#Department", cmbSRDepartment.Text),
new OleDbParameter("#StudentLevel", cmbSRLevel.Text),
new OleDbParameter("#AccomodationStatus", cmbSRAccomodationStatus.Text),
new OleDbParameter("#SemesterBill", txtSRSemesterBill.Text),
new OleDbParameter("#PreviousBalance", txtSRPreviousBalance.Text),
new OleDbParameter("#TotalBill", txtSRTotalBill.Text)
});
//Execute Query
cmd.ExecuteNonQuery();
//No need to close because we are using "using"
}
}
catch (OleDbException ex)
{
//If an exception occurs let's print it out to console
Console.WriteLine("ERROR: " + ex.ToString());
throw;
}
For information on how to change the column name read this:
https://msdn.microsoft.com/en-us/library/bb177883(v=office.12).aspx
"Level" is a keyword in MS Access, may be that is why this issue occurs try quoting it like [Level]
List Of MS Access Keywords

run multiple SqlCommand and ExecuteNonQuery

I am trying to run multiples SqlCommand in the same connection, but for some reason the program will stop at the second
command.ExecuteNonQuery();
Here is my code :
string queryString = "SELECT DISTINCT Titre from infosHoraire where Salle='DOO';" +
"SELECT DISTINCT Titre from infosHoraire where Salle='FOO' and Jour <='" + finDate + "';" +
"SELECT DISTINCT Titre from infosHoraire where Salle='GOO' and Jour <='" + finDate + "';";
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ConsoleXMLtoDB"].ConnectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
try
{
// on remplit le dico
while (reader.Read())
{
MoviesList.Add(reader[0].ToString(), "0");
searchCode(reader[0].ToString(), MoviesList);
//Console.WriteLine(" On rajoute le code {0}", MoviesList[reader[0].ToString()]);
}
reader.NextResult();
while (reader.Read())
{
if (!MoviesList.ContainsKey(reader[0].ToString()))
{
MoviesList.Add(reader[0].ToString(), "0");
searchCode(reader[0].ToString(), MoviesList);
}
}
reader.NextResult();
while (reader.Read())
{
if (!MoviesList.ContainsKey(reader[0].ToString()))
{
MoviesList.Add(reader[0].ToString(), "0");
}
}
foreach (string key in MoviesList.Keys)
{
Console.WriteLine("MoviesList {0}, code {1} .", key, MoviesList[key]);
// RAJOUTER DONNEES HORAIRES
command.CommandText = "INSERT INTO infosHoraire (Code) VALUES ('" + MoviesList[key] + "') where Titre = '" + key + "'";
//cmd.Parameters.AddWithValue("#code", MoviesList[key]);
IT STOPS HERE.
command.ExecuteNonQuery();
}
}
catch (Exception)
{
//Console.WriteLine("{0} Exception caught.", e);
}
finally
{
// Always call Close when done reading.
reader.Close();
connection.Close();
}
}
MoviesList is a
Dictionary<string, string>
I can't really find where the issue comes from.
It will work fine if I remove this :
foreach (string key in MoviesList.Keys)
{
//literaltest.Text += "<br/> dictionnaire " + key + "," + MoviesList[key];
Console.WriteLine("MoviesList {0}, code {1} .", key, MoviesList[key]);
// RAJOUTER DONNEES HORAIRES
command.CommandText = "INSERT INTO infosHoraire (Code) VALUES ('" + MoviesList[key] + "') where Titre = '" + key + "'";
//cmd.Parameters.AddWithValue("#code", MoviesList[key]);
command.ExecuteNonQuery();
}
Edit: Try to put a breakpoint on your catch and see if there is an error.
catch (Exception e)
{
//Console.WriteLine("{0} Exception caught.", e);
}
Hover your mouse on e and you should be able to see the error message. Then paste it here. Its probably your query causing the problem rather than the command object
Edit. The reader object is still running which is limiting you to use the command object again. Close the reader first before trying to execute the next command
reader.Close();
remove where condition from your following insert query
command.CommandText = "INSERT INTO infosHoraire (Code) VALUES ('" + MoviesList[key] + "') where Titre = '" + key + "'";
The SQLDataReader you used to read records is still open and using that connection. You need to close that reader before executing another command on the same connection. e.g.
reader.Close();
foreach (string key in MoviesList.Keys)
{
Console.WriteLine("MoviesList {0}, code {1} .", key, MoviesList[key]);
// RAJOUTER DONNEES HORAIRES
command.CommandText = "INSERT INTO infosHoraire (Code) VALUES ('" + MoviesList[key] + "') where Titre = '" + key + "'";
//cmd.Parameters.AddWithValue("#code", MoviesList[key]);
IT STOPS HERE.
command.ExecuteNonQuery();
}
Your SQL syntax for the INSERT statement is bad. You just need this
querystring= "INSERT INTO infosHoraire (Code) VALUES ('" + MoviesList[key] + "')";
The SqlCommand (command) is still busy - you can't reuse it for the insert statement. You'd need to open a new SqlConnection with a new SqlCommand. Although it'd probably be cleaner if you just moved your foreach outside of the original queries using block, since you only referencing the in memory dictionary at that point.
As mentioned, your insert statement also has a where clause which doesn't make sense...did you perhaps mean that to be an update statement?
Drop the empty catch and you'll see some exception messages, which will make your life much easier.
//edit your select statement try this
SELECT DISTINCT Titre from infosHoraire where Salle in ('DOO','FOO','GOO') and Jour <='" + finDate + "'";

Code repeating itself causing duplicate records in database

this problem is a bit of a difficult one to explain but here it goes. I have a function which adds a record to a MySQL Database online from a local SQLiteDatabase. A function is first called to retrieve the local data and each line is sent to the upload function which adds the record to the online MySQL Database. When these functions are called from a another function A it works fine but when called from a different function. Function B duplicate records are entered into the database.
During debugging to try and resolve the problem I find that when it is duplicating records it is going to cmd.executeNonQuery() then going to the next couple of line but then for no reason will go back up to cmd.executeNonQuery() therefore duplicating the record. The code is below
private void uploadDatabase(string company, string oldCompany, string companyURL, string loginUsername, string oldUsername, string password, string type, string perform, string direction)
{
Boolean recordFound = false;
recordFound = checkRecordNotExist(company, loginUsername);
MySQLDBWork dbase = new MySQLDBWork();
try
{
dbase.openConnection();
if (perform == "insert" && !recordFound)
{
string query = "INSERT INTO `" + username + "` (pas_company, pas_companyURL, pas_username, pas_password, pas_type) "
+ "VALUES ('" + company + "', '" + companyURL + "', '" + loginUsername + "', '" + password + "', '" + type + "')";
Console.WriteLine("Query: " + query);
MySqlCommand cmd = new MySqlCommand(query, dbase.conn);
cmd.ExecuteNonQuery();
recordFound = true;
query = "";
company = "";
loginUsername = "";
cmd.Dispose();
}
if (perform == "delete")
{
string query = "DELETE FROM `" + username + "` WHERE pas_company='" + company + "' AND pas_username='" + loginUsername + "'";
dbase.performQuery(query);
}
}
catch (MySqlException ex)
{
Console.WriteLine("Adding Online Error: " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("General Exception: " + ex.Message);
}
finally
{
dbase.closeConnection();
//dbase.conn.Dispose();
company = null;
loginUsername = null;
}
}
The problem is within the if statement perform == "insert" && !recordFound.
I'm not sure if the code above will help to solve the problem but this is the function that is going wrong when called from function b but works fine from function A. Thanks for any help and suggestions you can offer.
then going to the next couple of line
but then for no reason will go back up
to cmd.executeNonQuery()
That sounds like a simple multithreading problem. The function is accessed again from a different thread. So what's happening is that it goes through your check exists in both threads before it is inserted in either, and then it is inserted in both.
So, create a lock, and lock the code... something like this:
private System.Object uploadLock = new System.Object();
private void uploadDatabase(string company, string oldCompany, string companyURL, string loginUsername, string oldUsername, string password, string type, string perform, string direction)
{
lock(uploadLock ) {
Boolean recordFound = false;
recordFound = checkRecordNotExist(company, loginUsername);
MySQLDBWork dbase = new MySQLDBWork();
try
{
dbase.openConnection();
if (perform == "insert" && !recordFound)
{
string query = "INSERT INTO `" + username + "` (pas_company, pas_companyURL, pas_username, pas_password, pas_type) "
+ "VALUES ('" + company + "', '" + companyURL + "', '" + loginUsername + "', '" + password + "', '" + type + "')";
Console.WriteLine("Query: " + query);
MySqlCommand cmd = new MySqlCommand(query, dbase.conn);
cmd.ExecuteNonQuery();
recordFound = true;
query = "";
company = "";
loginUsername = "";
cmd.Dispose();
}
if (perform == "delete")
{
string query = "DELETE FROM `" + username + "` WHERE pas_company='" + company + "' AND pas_username='" + loginUsername + "'";
dbase.performQuery(query);
}
}
catch (MySqlException ex)
{
Console.WriteLine("Adding Online Error: " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("General Exception: " + ex.Message);
}
finally
{
dbase.closeConnection();
//dbase.conn.Dispose();
company = null;
loginUsername = null;
}
}
}
The lock will allow access to the code to only on thread at a time. So no more duplications.
My advice to you:
Always use transactions and you won't be able make duplications. You also may make LoginName column unique and properly handle db error.
DO NOT concatenate string to build query, please. Use command parameters - simplest way escape SQL injection. Currently you have at least 4 vulnerable parameter. Awesome ;)
I would suggest putting a breakpoint on cmd.ExecuteNonQuery(); and inspecting the call stack each time it is hit, paying special attention to the second/duplicate hit. Also pay attention to which thread the breakpoint is being hit on. Doing these things should point you to the problem.

Categories

Resources