OleDbCommand with ORACLE query not updating table - c#

I have tried everything, googled for days, but nothing I found helped me.
I have Oracle 9i db, table TIME_UNITS that have several fields - for my purposes I use only 3, defined as:
CODE - VARCHAR2(6), FOR_IN - VARCHAR2(1), FOR_OUT - VARCHAR2(1). My code is:
string strConString = "provider=MSDAORA;DSN=myDSN;user id=myUser;password=myPassword";
string strQuery = "UPDATE TIME_UNITS SET FOR_IN='Y', FOR_OUT='Y' WHERE CODE='202003'";
using (OleDbConnection oleDbConn = new OleDbConnection(strConString ))
using (OleDbCommand cmd = new OleDbCommand(strQuery, oleDbConn))
{
oleDbConn.Open();
cmd.Transaction = oleDbConn.BeginTransaction();
int rows = cmd.ExecuteNonQuery();
cmd.Transaction.Commit();
oleDbConn.Close();
}
ExecuteNonQuery returns one row, but when I look into db using sqldeveloper nothing is changed. The same statement works perfectly in sqldeveloper using the same credentials. I've tried with and without transaction begin-commit, but still no change in database. What am I doing wrong?

Related

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");
}

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

How do I insert the auto-increment ID into a MySQL table using MySQL ODBC with ASP.Net/C#?

I am using MySQL ODBC to insert data into a MySQL table. The first column in the table is an ID that is of type int and auto increments. When I insert the data for the very first row, what should the value be for #ReqID, as shown below? Also, how do I ensure that subsequent executions are auto incrementing for the ID?
Here is the C#:
string conString = WebConfigurationManager.ConnectionStrings["mysql"].ConnectionString;
using (OdbcConnection con = new OdbcConnection(conString))
{
con.Open();
using (OdbcCommand cmd = con.CreateCommand()) {
cmd.CommandText = "INSERT INTO GraphicsRequest (RequestID, Graphic1Desc, Graphic2Desc, Graphic3Desc, ColorChart, Hex1, Hex2, Hex3, Hex4) VALUES (#reqID, #g1d, #g2d, #g3d, #colorChart, #hex1, #hex2, #hex3, #hex4)";
cmd.Parameters.AddWithValue("#reqID", 1);
cmd.Parameters.AddWithValue("#g1d", txtGraphic1Desc.Text);
cmd.Parameters.AddWithValue("#g2d", txtGraphic2Desc.Text);
cmd.Parameters.AddWithValue("#g3d", txtGraphic3Desc.Text);
cmd.Parameters.AddWithValue("#colorChart", ddlColorChart.SelectedValue);
cmd.Parameters.AddWithValue("#hex1", lblColor1.Text);
cmd.Parameters.AddWithValue("#hex2", lblColor2.Text);
cmd.Parameters.AddWithValue("#hex3", lblColor3.Text);
cmd.Parameters.AddWithValue("#hex4", lblColor4.Text);
cmd.ExecuteNonQuery();
}
}
In MySQL you shouldn't supply the ID-field during an INSERT if you want to use the auto incrementing feature of the database itself.
So that would be in your case.
string conString = WebConfigurationManager.ConnectionStrings["mysql"].ConnectionString;
using (OdbcConnection con = new OdbcConnection(conString))
{
con.Open();
using (OdbcCommand cmd = con.CreateCommand()) {
cmd.CommandText = "INSERT INTO GraphicsRequest (Graphic1Desc, Graphic2Desc, Graphic3Desc, ColorChart, Hex1, Hex2, Hex3, Hex4) VALUES (#g1d, #g2d, #g3d, #colorChart, #hex1, #hex2, #hex3, #hex4)";
cmd.Parameters.AddWithValue("#g1d", txtGraphic1Desc.Text);
cmd.Parameters.AddWithValue("#g2d", txtGraphic2Desc.Text);
cmd.Parameters.AddWithValue("#g3d", txtGraphic3Desc.Text);
cmd.Parameters.AddWithValue("#colorChart", ddlColorChart.SelectedValue);
cmd.Parameters.AddWithValue("#hex1", lblColor1.Text);
cmd.Parameters.AddWithValue("#hex2", lblColor2.Text);
cmd.Parameters.AddWithValue("#hex3", lblColor3.Text);
cmd.Parameters.AddWithValue("#hex4", lblColor4.Text);
cmd.ExecuteNonQuery();
}
}
This way the database will INSERT a new row with the next available the ID for you.
Since the other have answered your question, I would suggest that you use the MySQL Connector in your project instead of using OLEDB objects. Download and install the MySQL Connector and then add a reference in your project to the MySQL.Data extension and then add the MySql.Data.MySqlClient using statement to your class and then update your code as follows:
string conString = WebConfigurationManager.ConnectionStrings["mysql"].ConnectionString;
using(MySqlConnection con = new MySqlConnection(connectionString))
{
con.Open();
using(MySqlCommand cmd = new MySqlCommand()
{
cmd.Connection = con; //<-- It looks like you are missing this line in your code
cmd.CommandText = "INSERT INTO GraphicsRequest (Graphic1Desc, Graphic2Desc, Graphic3Desc, ColorChart, Hex1, Hex2, Hex3, Hex4) VALUES (#g1d, #g2d, #g3d, #colorChart, #hex1, #hex2, #hex3, #hex4)";
cmd.Parameters.AddWithValue("#g1d", txtGraphic1Desc.Text);
cmd.Parameters.AddWithValue("#g2d", txtGraphic2Desc.Text);
cmd.Parameters.AddWithValue("#g3d", txtGraphic3Desc.Text);
cmd.Parameters.AddWithValue("#colorChart", ddlColorChart.SelectedValue);
cmd.Parameters.AddWithValue("#hex1", lblColor1.Text);
cmd.Parameters.AddWithValue("#hex2", lblColor2.Text);
cmd.Parameters.AddWithValue("#hex3", lblColor3.Text);
cmd.Parameters.AddWithValue("#hex4", lblColor4.Text);
cmd.ExecuteNonQuery();
}
}
probably this would solve the problem .
strong textcom.ExecuteNonQuery();
long id = com.LastInsertedId;

C# 'select count' sql command incorrectly returns zero rows from sql server

I'm trying to return the rowcount from a SQL Server table. Multiple sources on the 'net show the below as being a workable method, but it continues to return '0 rows'. When I use that query in management studio, it works fine and returns the rowcount correctly. I've tried it just with the simple table name as well as the fully qualified one that management studio tends to like.
using (SqlConnection cn = new SqlConnection())
{
cn.ConnectionString = sqlConnectionString;
cn.Open();
SqlCommand commandRowCount = new SqlCommand("SELECT COUNT(*) FROM [LBSExplorer].[dbo].[myTable]", cn);
countStart = System.Convert.ToInt32(commandRowCount.ExecuteScalar());
Console.WriteLine("Starting row count: " + countStart.ToString());
}
Any suggestions on what could be causing it?
Here's how I'd write it:
using (SqlConnection cn = new SqlConnection(sqlConnectionString))
{
cn.Open();
using (SqlCommand commandRowCount
= new SqlCommand("SELECT COUNT(*) FROM [LBSExplorer].[dbo].[myTable]", cn))
{
commandRowCount.CommandType = CommandType.Text;
var countStart = (Int32)commandRowCount.ExecuteScalar();
Console.WriteLine("Starting row count: " + countStart.ToString());
}
}
Set your CommandType to Text
command.CommandType = CommandType.Text
More Details from Damien_The_Unbeliever comment, regarding whether or not .NET defaults SqlCommandTypes to type Text.
If you pull apart the getter for CommandType on SqlCommand, you'll find that there's weird special casing going on, whereby if the value is currently 0, it lies and says that it's Text/1 instead (similarly, from a component/design perspective, the default value is listed as 1). But the actual internal value is left as 0.
You can use this better query:
SELECT OBJECT_NAME(OBJECT_ID) TableName, st.row_count
FROM sys.dm_db_partition_stats st
WHERE index_id < 2 AND OBJECT_NAME(OBJECT_ID)=N'YOUR_TABLE_NAME'

Cannot commit DataSet changes to database

I've written a small form that reads the data from a database table (SQL CE 3.5) and displays it in a DataGridView control. This works fine. I then modified it to make a change to the data before displaying it, which also seems to work fine with the exception that it doesn't seem to actually commit the changes to the database. The code is as follows:
using (SqlCeConnection conn = new SqlCeConnection(
Properties.Settings.Default.Form1ConnectionString
)) {
conn.Open();
using (SqlCeDataAdapter adapter = new SqlCeDataAdapter(
"SELECT * FROM People", conn
)) {
//Database update command
adapter.UpdateCommand = new SqlCeCommand(
"UPDATE People SET name = #name " +
"WHERE id = #id", conn);
adapter.UpdateCommand.Parameters.Add(
"#name", SqlDbType.NVarChar, 100, "name");
SqlCeParameter idParameter = adapter.UpdateCommand.Parameters.Add(
"#id", SqlDbType.Int);
idParameter.SourceColumn = "id";
idParameter.SourceVersion = DataRowVersion.Original;
//Create dataset
DataSet myDataSet = new DataSet("myDataSet");
DataTable people = myDataSet.Tables.Add("People");
//Edit dataset
adapter.Fill(myDataSet, "People");
people.Rows[0].SetField("name", "New Name!");
adapter.Update(people);
//Display the table contents in the form datagridview
this.dataGridView1.DataSource=people;
}
}
The form displays like so:
Looking at the table via Visual Studio's Server Explorer however, doesn't show any change to the table.
What am I doing wrong?
I found it. It took days but I found it.
Properties.Settings.Default.Form1ConnectionString is "Data Source=|DataDirectory|\Form1.sdf". The update works if I replace the automatically generated "|DataDirectory|" with the actual path. Oddly enough reading from the database works either way.
Shouldn't the update line be
adapter.Update(myDataSet, "People")
I would make sure the DataSet believes it's been changed. Invoke DataSet.HasChanges (returns bool) and DataSet.GetChanges, which returns a delta of the DataSet from the original.
Have you also tried this against Sql Server Express just to eliminate any issues with the CE data adapter?

Categories