MySqlCommand Prepare() never sets IsPrepared to true - c#

Here's the issue: no matter what I seem to do, I can't get a MySqlCommand to actually prepare. I've tried copy/pasting the example code from http://dev.mysql.com/doc/refman/5.6/en/connector-net-programming-prepared.html with very slight modifications, but that does not actually work either.
I scoured Google to try and find a solution, but the closest thing that came up was: MySql statement prepare "not sticking" which did not actually answer the question.
Here's my table setup for this test:
CREATE TABLE `test`.`test_prepared_query` (
`id` INT NOT NULL ,
`value` INT NOT NULL ,
PRIMARY KEY (`id`) );
Test code in C#
public void TestPrepareQuery()
{
connString = new MySqlConnectionStringBuilder();
connString.Server = "localhost";
connString.Database = "test";
connString.UserID = "someuserid";
connString.Password = "somepassword";
bool isprepared;
using (MySqlConnection conn = new MySqlConnection(connString.ToString()))
{
MySqlCommand cmd = new MySqlCommand(
"INSERT INTO test_prepared_query VALUES (#id, #value)", conn);
cmd.Connection.Open();
cmd.Prepare();
isprepared = cmd.IsPrepared; // isprepared is false here
cmd.Parameters.AddWithValue("#id", 0);
cmd.Parameters.AddWithValue("#value", 0);
cmd.Prepare();
isprepared = cmd.IsPrepared; // isprepared is still false
// this is 1 -- the query succeeds
int rowsAffected = cmd.ExecuteNonQuery();
for (int i = 1; i < 10; i++)
{
cmd.Parameters["#id"].Value = i;
cmd.Parameters["#value"].Value = i;
// this is 1 -- the query succeeds
rowsAffected = cmd.ExecuteNonQuery();
}
}
}
When I run the code, it does successfully put rows in the table, but stepping through the program reviews that the state of cmd.IsPrepared is always false. Does anyone know why this could be happening? This source code is essentially identical to the example code, with only modifications to the table name as well as real connection strings.
Edit:
I've tried variables with ?name format, and that does not work either. I've also tried only having one cmd.Prepare() method call at a time in the tests.

I eventually pulled up the source code for MySql Connector / .NET and discovered that if MySqlCommand.Connection.Settings.IgnorePrepare = true (which is the default!), then calling Prepare is a no op.
The way to fix this is to explicitly set IgnorePrepare to false in the connection string. This can be done rather easily with a MySqlConnectionStringBuilder using the following code snippet:
MySqlConnectionStringBuilder connBuilder = new MySqlConnectionStringBuilder();
// .. set up the rest of your connection
connBuilder.IgnorePrepare = false;
MySqlConnection conn = new MySqlConnection(connBuilder.ToString());

Related

C# Web Forms : Update Set doesn't update Row

I am using ASP .NET Web Forms . I have 8 Textboxes in which the user can input data for a specific row on the SQL and make changes on the database accordingly for a car, with make, model, year, engine, the rate, availability and location.
I am using the Update Set SQL query as seen on the code line "string query" but it doesn't do anything to the database.
I have established a connection on the SQL Server with Visual Studio 2022
string a = TextBox1.Text;
string b = TextBox2.Text;
string c = TextBox3.Text;
string d = TextBox4.Text;
string ee = TextBox5.Text;
string f = TextBox6.Text;
string g = TextBox7.Text;
string h = TextBox8.Text;
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["TLESConnectionString"].ConnectionString);
conn.Open();
string query = "UPDATE MyCar SET Make = #Make, Model = #Model, Year = #Year ,Engine = #Engine , Rate = #Rate ,Availability = #Availability , Location = #Location";
SqlCommand com = new SqlCommand(query, conn);
com.Parameters.AddWithValue("#Make", a);
com.Parameters.AddWithValue("#Model", b);
com.Parameters.AddWithValue("#Year", c);
com.Parameters.AddWithValue("#Engine", d);
com.Parameters.AddWithValue("#Rate", ee);
com.Parameters.AddWithValue("#Availability", f);
com.Parameters.AddWithValue("#Location", g);
conn.Close();
What is your suggestion as to why it is not updating the Row ?
Your code is missing a few aspects. You are defining the query, which is correct, and you set the parameters and values correctly. You never execute the query, however, and after setting the variables, you close the connection.
I copied your code, made these changes, and it worked for me. Give it a try.
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["TLESConnectionString"].ConnectionString);
conn.Open();
string query = "UPDATE MyCar SET Make = #Make, Model = #Model, Year = #Year ,Engine = #Engine , Rate = #Rate ,Availability = #Availability , Location = #Location";
SqlCommand com = new SqlCommand(query, conn);
com.Parameters.AddWithValue("#Make", a);
com.Parameters.AddWithValue("#Model", b);
com.Parameters.AddWithValue("#Year", c);
com.Parameters.AddWithValue("#Engine", d);
com.Parameters.AddWithValue("#Rate", ee);
com.Parameters.AddWithValue("#Availability", f);
com.Parameters.AddWithValue("#Location", g);
com.ExecuteNonQuery();
As you can see, after inputting all of the variables, I am executing the query, thus making it work. You were just missing:
com.ExecuteNonQuery();
Well done so far.
Dont you need to add a condition as to where you want to update the values?
Example from w3schools
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
Also have you checked if the connection string and the query are both correct?
You can use the Debug for that, check the string value / content for both the connection and the query
On top of that, I noticed that you opened a connection and created a Command, but you didnt run the command, you close the connection, are you running the command?
You could do that with:
try
{
Com.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
EDIT: You only need to use the 'Where' clause if you want to update a specific value rather than the entire table, If you omit the 'WHERE' clause, ALL records will be updated

C# MS SQL Update statement not updating database

I have a local MS SQL Database, and I want to update one of it's bit field.
I have the following code:
static void UpgradeVevo(string nev)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand("UPDATE Vevok SET Torzsvendeg=True Where Nev=" + nev, connection);
command.ExecuteNonQuery();
}
Console.WriteLine(nev+" mostmár törzsvendég");
}
Torzsvendeg is a bit datatype(I have tried to set its value to 1 too), and Nev is varchar.
The connectionstring should be fine, since I have tried Select in another method and it works fine. The above code throws no exceptions, but the table does not get updated.
I have tried to find an answer for quite some time, with no success :/. Thank you for your help in advance!
True should be in a single quote since it's a string literal like
UPDATE Vevok SET Torzsvendeg='True'
Well brother, you are messed up with quotes. Your query should look like
"UPDATE Vevok SET Torzsvendeg = 1 Where Nev = '" + nev + "'"
Again, use parametarized query and not this concatenated one to avoid SQL Injection
If the column is a boolean (bit in sql server) then you will have to write
Torzsvendeg=1
instead of
Torzsvendeg='True'
or
Torzsvendeg=True
Edit:
Please try this:
static void UpgradeVevo(string nev)
{
var connection = new SqlConnection(connectionString))
connection.Open(); // try doing this without a using
SqlCommand command = new SqlCommand("UPDATE Vevok SET Torzsvendeg=#enabled Where Nev=#nev", connection);
command.Parameters.AddWithValue(#"enabled", 1);
command.Parameters.AddWithValue(#"nev", "vevo123");
command.ExecuteNonQuery();
command.Parameters.Clear(); // always clear after executed
// close connection when you shut down your application
connection.Close();
connection.Dispose();
Console.WriteLine(nev+" mostmár törzsvendég");
}

Getting column information in SQL

I am somwhat new to SQL, so I am not sure I am going about this the right way.
I am trying to fetch data from my SQL Server database where I want to find out if checkedin is 1/0, but it needs to search on a specific user and sort after the newest date as well.
What I am trying to do is something like this:
string connectionString = ".....";
SqlConnection cnn = new SqlConnection(connectionString);
SqlCommand checkForInOrOut = new SqlCommand("SELECT CHECKEDIN from timereg ORDER BY TIME DESC LIMIT 1 WHERE UNILOGIN = '" + publiclasses.unilogin + "'", cnn);
So my question, am I doing this right? And how do I fetch the data collected, if everything was handled correctly it should return 1 or 0. Should I use some sort of SqlDataReader? I am doing this in C#/WPF
Thanks
using (SqlDataReader myReader = checkForInOrOut.ExecuteReader())
{
while (myReader.Read())
{
string value = myReader["COLUMN NAME"].ToString();
}
}
This is how you would read data from SQL, but i recommend you looking into Parameters.AddWithValue
There are some errors in your query. First WHERE goes before ORDER BY and LIMIT is an MySql keyword while you are using the Sql Server classes. So you should use TOP value instead.
int checkedIn = 0;
string cmdText = #"SELECT TOP 1 CHECKEDIN from timereg
WHERE UNILOGIN = #unilogin
ORDER BY TIME DESC";
string connectionString = ".....";
using(SqlConnection cnn = new SqlConnection(connectionString))
using(SqlCommand checkForInOrOut = new SqlCommand(cmdText, cnn))
{
cnn.Open();
checkForInOrOut.Parameters.Add("#unilogin", SqlDbType.NVarChar).Value = publiclasses.unilogin;
// You return just one row and one column,
// so the best method to use is ExecuteScalar
object result = checkForInOrOut.ExecuteScalar();
// ExecuteScalar returns null if there is no match for your where condition
if(result != null)
{
MessageBox.Show("Login OK");
// Now convert the result variable to the exact datatype
// expected for checkedin, here I suppose you want an integer
checkedIN = Convert.ToInt32(result);
.....
}
else
MessageBox.Show("Login Failed");
}
Note how I have replaced your string concatenation with a proper use of parameters to avoid parsing problems and sql injection hacks. Finally every disposable object (connection in particular) should go inside a using block

ODAC seems to be caching table schema?

I'm using Oracle's ODAC.NET for a .NET 3.5 project against an Oracle 11 Express database, and I'm seeing behavior that I can't explain (and can't seem to work around).
ODAC should be the latest, I just pulled it 3 days ago, but the versions are as follows:
Oracle.DataAccess.dll version 2.112.3.0 (release 5)
oci.dll (instant client) version 11.2.0.1
I have a Table, People, that has 3 columns:
ID
FirstName
LastName
In code I run an ALTER TABLE command, using OracleCommand.ExecuteNonQuery, to add a new column named "MIDDLE_NAME" to the table. That command succeeds. If I look at the table with Oracle SQL Developer, the columns shows up. All well and good.
Now if I run use OracleCommand.ExecuteReader with a command text of SELECT * FROM People right after I do the alter table, I get back data with only 3 columns, not 4!
Here is code that reproduces the problem:
public void FieldTest()
{
var sql1 = "CREATE TABLE People (" +
"ID NUMBER PRIMARY KEY, " +
"FirstName NVARCHAR2 (200), " +
"LastName NVARCHAR2 (200) NOT NULL)";
var sql2 = "ALTER TABLE People " +
"ADD Middle_Name NUMBER";
var sql3 = "SELECT * FROM People";
var sql4 = "SELECT column_name FROM all_tab_cols WHERE table_name = 'PEOPLE'";
var cnInfo = new OracleConnectionInfo("192.168.10.246", 1521, "XE", "system", "password");
var connectionString = BuildConnectionString(cnInfo);
using (var connection = new OracleConnection(connectionString))
{
connection.Open();
using (var create = new OracleCommand(sql1, connection))
{
create.ExecuteNonQuery();
}
using (var get = new OracleCommand(sql3, connection))
{
using (var reader = get.ExecuteReader())
{
Debug.WriteLine("Columns: " + reader.FieldCount);
// outputs 3, which is right
}
}
using (var alter = new OracleCommand(sql2, connection))
{
alter.ExecuteNonQuery();
}
using (var get = new OracleCommand(sql3, connection))
{
using (var reader = get.ExecuteReader())
{
Debug.WriteLine("Columns: " + reader.FieldCount);
// outputs 3, which is *wrong* <---- Here's the problem
}
}
using (var cols = new OracleCommand(sql4, connection))
{
using (var reader = cols.ExecuteReader())
{
int count = 0;
while (reader.Read())
{
count++;
Debug.WriteLine("Col: " + reader.GetString(0));
}
Debug.WriteLine("Columns: " + count.ToString());
// outputs 4, which is right
}
}
}
}
I've tried some things to prevent the behavior, and none of them give me back the 4th column:
I close the connection and re-open it
I use a new OracleConnection for the SELECT than for the ALTER
I use the same OracleConnection for the SELECT and for the ALTER
I use a new OracleCommand for the SELECT than for the ALTER
I use the same OracleCommand for the SELECT and for the ALTER
I call PurgeStatementCache on the connection between the ALTER and SELECT
I call FlushCache on the connection between the ALTER and SELECT
I explicitly Close and Dispose the OracleCommand and OracleConnection (as opposed to the using block) used for the ALTER and SELECT
Restarted the calling PC and the PC hosting the Oracle database.
If I look at the column list by doing a SELECT * FROM all_tab_cols, the new column is there.
The only thing that seems to work reliably is closing the app and re-starting it (well it's from a unit test, but it's a shutdown and restart of the test host). Then I get that 4th column. Sometimes I can use breakpoints and re-execute queries and the 4th column will appear, but nothing that is specifically repeatable with straight execution of code (meaning without setting a break point and moving the execution point back up).
Something in the bowels of ODAC seems to be caching the schema of that table, but I can figure out what, why or how to prevent it. Anyone have any experience with this, or ideas how I might prevent it?
I know this answer comes years later but if new readers run into problems with caching try setting:
Metadata Pooling = false, Self Tuning = False and Statement Cache Size = 0
...in the connection string. Keep in mind that there are performance implications for doing so.
https://docs.oracle.com/database/122/ODPNT/featConnecting.htm#GUID-0CFEB161-68EF-4BC2-8943-3BDFFB878602
Maybe post some of your C# code. The following is a test that behaves as expected, meaning I can see the new column immediately after adding it. This is using odp 11.2 rel 5 hitting an 11g db, using 4.0 framework:
The test table is:
CREATE TABLE T1
(
DTE DATE default sysdate
);
Drop and recreate it after each run of the following C# code (a bit dirty but anyway):
string connStr = "User Id=xxx;Password=yyy;Data Source=my11gDb;";
using (OracleConnection con = new OracleConnection(connStr))
{
string s = "ALTER TABLE T1 ADD (added_col VARCHAR2(10))";
using (OracleCommand cmd = new OracleCommand(s, con))
{
con.Open();
cmd.ExecuteNonQuery();
string s2 = "select column_name from all_tab_columns where table_name = 'T1'";
//con.FlushCache(); // doesn't seem to matter, works with or without
using (OracleCommand cmd2 = new OracleCommand(s2, con))
{
OracleDataReader rdr = cmd2.ExecuteReader();
for (int i = 0; rdr.Read(); i++)
{
Console.WriteLine("Column {0} => {1}",i+1,rdr.GetString(0));
}
rdr.Close();
}
}
}
Output:
Column 1 => DTE
Column 2 => ADDED_COL
Edit:
Ah, ok, I see what you're saying, it looks like statement caching. I played around with changing the cache size to 0 (in conn string, use "Statement Cache Size=0"), and also tried cmd.AddToStatementCache = false, but these did not work.
One thing that does work is to use a slightly different string, like adding a space. I know its a hack, but this is all I can get to work for me anyway.
Try your example with:
var sql3 = "SELECT * FROM People";
var sql5 = "SELECT * FROM People "; // note extra space
And use sql3 before adding column, and sql5 after adding a column.
Hope that helps

Sql UPDATE command has no effect and throws no error only in web page, same code in console project works

I have a .NET 3.5 web application which has a set of classes handling entity persistence. The INSERT and SELECT prepared commands work. However the UPDATE command never works (no database record is updated) and it never throws an exception. Also it always returns 1, so even the command.ExecuteNonQuery() returns a valid number of affected rows.
Now when I take the same entity class and run it in a test console application, the prepared statement works.
This is really frustrating and a complete show stopper. I have even tried this in Mono on Ubuntu, Mac OS X and Windows. All perform the same (no records updated in web app, insert works, and console app works).
public void Store()
{
SqlConnection conn = new SqlConnection(this.connection_string);
conn.Open();
SqlCommand cmd = conn.CreateCommand();
int i = 0;
if (this.id == 0)
{
// INSERT a new RECORD
cmd.CommandText = "INSERT INTO [VtelCenter] ([CommonName],[Location]) VALUES (#commonname, " +
"#location)";
cmd.Parameters.Add("#commonname", SqlDbType.NVarChar, this.CommonName.Length);
cmd.Parameters["#commonname"].Value = this.CommonName;
cmd.Parameters.Add("#location", SqlDbType.NVarChar, this.Location.Length);
cmd.Parameters["#location"].Value = this.Location;
}
else
{
// UPDATE an existing RECORD
cmd.CommandText = "UPDATE [VtelCenter] SET [CommonName] = #commonname, [Location] = #location, " +
"[Status] = #status WHERE [ID] = #id";
//cmd.CommandText = "EXEC [dbo].[UpdateVtelCenter] #id, #commonname, #location, #status";
cmd.Parameters.Add("#commonname", SqlDbType.NVarChar, this.commonName.Length);
cmd.Parameters["#commonname"].Value = this.CommonName;
cmd.Parameters.Add("#location", SqlDbType.NVarChar, this.Location.Length);
cmd.Parameters["#location"].Value = this.Location;
cmd.Parameters.Add("#status", SqlDbType.Int);
cmd.Parameters["#status"].Value = (int) this.Status;
cmd.Parameters.Add("#id", SqlDbType.Int);
cmd.Parameters["#id"].Value = this.Id;
}
cmd.Prepare();
i = cmd.ExecuteNonQuery();
if (i != 1)
throw new Exception(string.Format("Incorrect number of records stored: {0}, should be 1.", i));
conn.Close();
}
A couple of thoughts to help with debugging this.
Look for any UPDATE triggers (either AFTER or INSTEAD OF) on the VtelCenter table that might be changing your expected results.
Run a SQL Profiler trace on your database server so you can capture the query being passed in on that side.

Categories