Prepared MySQL Statement fails insert with no error - c#

I'm using MySQL to try and add a new user to my database. User got an Id, a First Name, a Last Name and a Date of Birth. But when I run the code below (And run conn.close() after I'm done) the database tells me (using HeidiSQL) that in the Table Overview there is now a new row in the table but when I open the Data Tab to look at the rows, there is nothing. It's empty. Running a COUNT(*) also returns 0.
using (MySqlTransaction transaction = conn.BeginTransaction())
{
using (MySqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "INSERT INTO USERS(NAME_FIRST,NAME_LAST,DATE_OF_BIRTH) VALUES(#nameFirst,#nameLast,#dateOfBirth)";
cmd.Transaction = transaction;
cmd.Parameters.AddWithValue("#nameFirst", user.NameFirst);
cmd.Parameters.AddWithValue("#nameLast", user.NameLast);
cmd.Parameters.AddWithValue("#dateOfBirth", user.DateOfBirth);
cmd.Prepare();
cmd.ExecuteNonQuery();
lastInsertId = (uint)cmd.LastInsertedId;
}
}
I get no errors. Nothing shows up in any log and everyone sees the same as me.
What am I doing wrong?

It feels like it's the use of begintransaction which starts a transaction. This means autocommit=false for the entirety of the transaction.
After ExecuteNonQuery Do a transaction.Commit(); and see if they show up.
More Info Here

Related

How to fix my update statement in C# API?

I wrote this below code and I am not able to update fields.
There is no error message, however my data is not getting updated.
public void UpdateTeacher(int id, [FromBody]Teacher TeacherInfo)
{
MySqlConnection Conn = Teachers.AccessDatabase();
//Open the connection between the web server and database.
Conn.Open();
//Establish a new command(query) for our database.
MySqlCommand cmd = Conn.CreateCommand();
cmd.CommandText = "update teachers set teacherfname=TeacherFname, teacherlname=TeacherLname, employeenumber=EmployeeNumber,salary=Salary where teacherid=TeacherId";
cmd.Parameters.AddWithValue("#TeacherFname", TeacherInfo.TeacherFname);
cmd.Parameters.AddWithValue("#TeacherLname", TeacherInfo.TeacherLname);
cmd.Parameters.AddWithValue("#EmployeeNumber", TeacherInfo.EmployeeNumber);
cmd.Parameters.AddWithValue("#Salary", TeacherInfo.Salary);
cmd.Parameters.AddWithValue("#TeacherId", id);
cmd.Prepare();
cmd.ExecuteNonQuery();
Conn.Close();
}
I tried insert and delete, they are working, however update query is not working.
If you look at how you are adding your parameters, you stated that the parameter name starts with an '#' symbol.
cmd.Parameters.AddWithValue("#TeacherFname", TeacherInfo.TeacherFname);
...
But if you look at your SQL text, you have not used the '#' symbol, so you need to add this at the front of all your parameter names.
cmd.CommandText = "update teachers set teacherfname=#TeacherFname, teacherlname=#TeacherLname, employeenumber=#EmployeeNumber,salary=#Salary where teacherid=#TeacherId";
As also stated in the comments, using AddWithValue is generally considered bad. See this for more details:
https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/

System.Data.SqlClient.SqlException: 'Incorrect syntax near ','.'

I have created this code to add new records to the database however, every time I rum the code I get this error:
System.Data.SqlClient.SqlException: 'Incorrect syntax near ','.'
And I have no idea how to fix this error, I have looked online and tried different ways to fix it and none of them helped or fixed the problem.
The code is found below:
SqlCommand sdk = new SqlCommand("SELECT ([Id],[Title],[JobInfo],[DateSet],[DateDue],[WhoFor]) FROM Information_Schema.Columns FROM JobInformation", ConnectToDatabase);
ConnectToDatabase.Open();
SqlDataReader reader;
reader = sdk.ExecuteReader();
ConnectToDatabase.Close();
I believe it to be the first line of code, but I have no clue where the error could be within it.
I expect you mean something like:
ConnectToDatabase.Open();
using(var sdk = new SqlCommand(
"SELECT [Id],[Title],[JobInfo],[DateSet],[DateDue],[WhoFor] FROM JobInformation",
ConnectToDatabase))
using(var reader = sdk.ExecuteReader())
{
while(reader.Read()) { /* process row */
}
ConnectToDatabase.Close();
However, you may find it easier to use a tool like dapper:
var jobs = ConnectToDatabase.Query<JobInfo>(
"SELECT [Id],[Title],[JobInfo],[DateSet],[DateDue],[WhoFor] FROM JobInformation"
).AsList();
(which does everything including the open/close, and populates the columns into your own JobInfo type that you need to create)
However, you say:
I have created this code to add new records to the database
in which case you'll need to use insert, not select - and the ExecuteNonQuery method of SqlCommand (or the Execute method of "dapper").
For an insert:
using(var cmd = new SqlCommand(#"
insert JobInformation(Title, JobInfo, DateSet, DateDue, WhoFor)
values (#title, #jobInfo, #dateSet, #dateDue, #whoFor)", ConnectToDatabase))
{
cmd.Parameters.AddWithValue("#title", title);
cmd.Parameters.AddWithValue("#jobInfo", jobInfo);
cmd.Parameters.AddWithValue("#dateSet", dateSet);
cmd.Parameters.AddWithValue("#dateDue", dateDue);
cmd.Parameters.AddWithValue("#whoFor", whoFor);
cmd.ExecuteNonQuery();
}
or with dapper:
ConnectToDatabase.Execute(#"
insert JobInformation(Title, JobInfo, DateSet, DateDue, WhoFor)
values (#title, #jobInfo, #dateSet, #dateDue, #whoFor)",
new { title, jobInfo, dateSet, dateDue, whoFor});

UPSERT query/syntax in OLE DB (MS Access)

For SQL Server, I could do this
UPDATE [Table] SET b=2, c=3 WHERE a=1;
IF ##ROWCOUNT=0
INSERT INTO [Table] (a,b,c) VALUES (1,2,3)
How do you do a similar thing on MS Access (using OleDbConnection)?
Doing that I got
Characters found after end of SQL statement.
I don't think the Jet/ACE OleDB engine has an equivalent of T-SQL syntax for this kind of problem.
You should go for the long route of checking if record exist, then decide for INSERT or UPDATE.
However, being Access mainly a single/local user database system you should not have many problems doing something like this pseudocode:
using(OleDbConnection cn = new OleDbConnection(constring))
{
cn.Open();
using(OleDbCommand cmd = new OleDbCommand("select count(*) from table where pkID = ?", cn);
{
cmd.Parameters.AddWithValue("pk", myID);
int result = Convert.ToInt32(cmd.ExecuteScalar());
if(result == 0)
// do your insert command here
else
// do your update command here
}
}
Of course, as I have said, this doesn't take into account concurrency problems.

How to configure MySQL to rollback when using TransactionScope?

I've spent a week trying to get transactions working for my MySQL database. Still no success. Running Windows 7 x64, MySQL Server 5.6.7-rc and MySQL .NET Connector 6.6.4.
MySQL claims that TransactionScope is supported (I've read the entire Internet by now), so I'm guessing I need some kind of special configuration to get it working. Here's what I've tried so far:
autocommit=0
In my.ini I've added autocommit=0 below the [mysqld] section.
In my.ini I've added init_connect='SET autocommit=0' below the [mysqld] section.
In Service Manager, I've added --autocommit=0 as a command line parameter.
I've verified that SELECT ##autocommit returns 0.
sql_mode=TRADITIONAL
In my.ini I've added sql-mode="TRADITIONAL" below the [mysqld] section.
In Service Manager, I've added --sql-mode=TRADITIONAL as a command line parameter.
Distributed Transaction Coordinator
I've tried enabling/disabling the DTC service.
The sample below throws an exception (System.Transactions.TransactionException exceptions must be enabled via Ctr+Alt+E) immediately when calling Open(). The error message is The operation is not valid for the state of the transaction.. Obviously, the server is not happy with the transaction stuff - which is proven by the fact that a rollback does NOT occur.
var factory = System.Data.Common.DbProviderFactories.GetFactory("MySql.Data.MySqlClient");
using (var transaction = new System.Transactions.TransactionScope())
{
var connection = factory.CreateConnection();
connection.ConnectionString = "Server=localhost;Port=3306;Database=test;User ID=user;Password=user";
connection.Open(); // <-- silent TransactionException here!
var command = connection.CreateCommand();
command.CommandText = "CREATE TABLE TestTable (ID INT) ENGINE = InnoDB DEFAULT CHARSET=utf8;";
command.ExecuteNonQuery();
command.CommandText = "INSERT INTO TestTable (ID) VALUES (123);";
command.ExecuteNonQuery();
// ATTENTION! This should imply a rollback!
// transaction.Complete();
}
The sample code works for SQL Server so I know for sure that this problem has something to do with MySQL.
QUESTION: I've tried everything. What do I need to do to get this TransactionScope code working for MySQL?
MySQL will automatically commit the active transaction on executing a DDL statement (see http://dev.mysql.com/doc/refman/5.5/en/cannot-roll-back.html). So anything after the CREATE TABLE will not be part of the transaction.
The same thing would happen if you performed the SQL statements as follows:
START TRANSACTION;
CREATE TABLE TestTable (ID INT) ENGINE = InnoDB DEFAULT CHARSET=utf8;
INSERT INTO TestTable (ID) VALUES (123);
ROLLBACK;
Try changing your code to:
var factory = MySqlClientFactory.Instance;
string connectionString = "Server=localhost;Port=3306;Database=test;User ID=user;Password=user";
// DDL cannot be performed in transaction as will commit
using (var connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
connection.Open();
var command = connection.CreateCommand();
command.CommandText = "CREATE TABLE TestTable (ID INT) ENGINE = InnoDB DEFAULT CHARSET=utf8;";
command.ExecuteNonQuery(); // will always commit here
}
// DML can be performed in transaction
using (var transaction = new System.Transactions.TransactionScope())
using (var connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
connection.Open();
var command = connection.CreateCommand();
command.CommandText = "INSERT INTO TestTable (ID) VALUES (123);";
command.ExecuteNonQuery();
// should rollback here
//transaction.Complete();
}

C# .net Concurrency Problems - SQL Connection then ADO.net changes

I have a c# .net program where I need to first insert data into a table using a sql connection and then adjust the same set of data using ADO.net. I am not sure how to make sure the insert via the sql connection is complete before doing the ado.net changes. I am getting a concurrency violation when I try the code below. I would guess that this is a race condition problem.
I am getting a concurrency violation error at the point of the UpdateAll statement and I can't seem to work around it
Thanks for the help.
Below is an example of the code with the SQL and ado.net changes dramatically simplified.
try
{
String deleteQuery = "DELETE FROM dbo.TABLENAME";
String reportQuery = #"
INSERT INTO TABLENAME
(
COLUMN1,
COLUMN2,
COLUMN3
)
SELECT
COLUMN1,
COLUMN2,
COLUMN3
FROM OTHERTABLES
";
SqlConnection ReportConnect = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.Text;
cmd.Connection = ReportConnect;
cmd.CommandTimeout = Convert.ToInt32(Properties.Settings.Default.ReportTimeout.ToString());
ReportConnect.Open();
cmd.CommandText = deleteQuery;
cmd.ExecuteNonQuery();
cmd.CommandText = reportQuery;
cmd.ExecuteNonQuery();
ReportConnect.Close();
ReportConnect.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
try
{
foreach (DataRow dr in DataSet.TABLENAME)
{
dr[0] = whatever;
dr[0] = 100;
dr[0] = 42.42;
}
}
catch (Exception ax)
{
MessageBox.Show(ax.Message);
}
finally
{
this.tableAdapterManager.UpdateAll(this.DataSet);
}
The problem here is that the "tableAdapterManager" appears to be created and opened before the data changes are made (with the sqlcommand). If you create the SqlDataAdapter with the wizard, by default the concurrency mode is optimistic (so the update and delete statement detect if the database has changed...) and fails with the exception you expose.
You can solve this issue in the wizard windows "Generate the SQL statements", click on the "Advanced Options" and uncheck the "Use optimistic concurrency" option.
Also you can change this from the form.designes.cs file, look for the UpdateCommand of the SqlDataAdapter and make sure that in the creation of the SqlParameter the DataRowVersion is set to "Default" or use another constructor.
In theory ExecuteNonQuery would not complete until the SQL had run, rendering your question moot. If you were deliberately executing asynchronously it would be a different matter, but you're not.
You should still be aware of issues caused by multiple concurrent users, of course.

Categories

Resources