Simple SQL Update statements occassionally working in MS Access? - c#

Problem I have is when I run a SQL UPDATE on different fields, but the same WHERE criteria in my SQL statement one produces a change, and the other does not.
This produces no rows affected:
DateTime now = DateTime.Now;
OleDbCommand cmd = new OleDbCommand("UPDATE shifts SET end_log=#end_log WHERE profile_id=#profile_id;");
cmd.Parameters.AddWithValue("#profile_id", profileID); // profileID is a string
cmd.Parameters.AddWithValue("#end_log", now.ToString());
Whereas if I ran this, one row is affected:
OleDbCommand cmd = new OleDbCommand("UPDATE shifts SET closing=true WHERE profile_id=#profile_id;");
cmd.Parameters.AddWithValue("#profile_id", profileID);
My shifts table has the following fields:
profile_id - Short Text
end_log - Date/Time
closed - Yes/No
You can assume the tables hold the same data in both instances (this is automatically loaded and only contains one record).
Anyone spot any errors?

While using OLEDB provider order of parameters is important.
Instead of
OleDbCommand cmd = new OleDbCommand("UPDATE shifts SET end_log=#end_log WHERE profile_id=#profile_id;");
cmd.Parameters.AddWithValue("#profile_id", profileID); // profileID is a string
cmd.Parameters.AddWithValue("#end_log", now.ToString());
try
OleDbCommand cmd = new OleDbCommand("UPDATE shifts SET end_log=#end_log WHERE profile_id=#profile_id;");
cmd.Parameters.AddWithValue("#end_log", now.ToString());
cmd.Parameters.AddWithValue("#profile_id", profileID); // profileID is a string
Order in which parameters are added to Parameters collection should match order in which parameters appear in the query.

Related

Datarow id string not matching with object id string even though they are identical strings after checking debug

I am trying to search through a list of ID strings in my database where an ID string is equal to the one of the object i am trying to create. The id being created is in a factory design pattern where a train type "express" is made with an ID of "1E45". After this ID is created, it increments the number section after the letter and then that can be used for the next train added.
When searching through the list with a foreach it returns the id from the database that is similar to the one trying to be created.
But when I try to match these two after using toString to change them both and match in an IF. The match returns false even though when I check the debug it is exactly the same?
It then just continues on to try and add a new object with that ID that already exists and crashes.
What am I doing wrong? it doesn't make sense after checking the values being matched and it saying false.
Here is the code I have set up:
//Create sql command variables to create new commands
SqlCommand insert = new SqlCommand();
SqlCommand checkID = new SqlCommand();
//Set the command type to text
insert.CommandType = CommandType.Text;
checkID.CommandType = CommandType.Text;
//Searches for an ID in the database that matches one that is trying to be created
checkID.CommandText = "SELECT id FROM Train WHERE id = #trainID";
//Parameters for checking ID in database
checkID.Parameters.AddWithValue("#trainID", train.TrainID);
//Set the connection for the command for the checkID sql connection
checkID.Connection = con;
//Start the connection
con.Open();
DataTable dt = new DataTable();
SqlDataAdapter adapter = new SqlDataAdapter(checkID);
adapter.Fill(dt);
dt.Load(checkID.ExecuteReader());
//Item last = Module.
foreach (DataRow i in dt.Rows)
{
if (i.ToString() == train.TrainID.ToString())
{
MessageBox.Show("This ID already exists! " + train.TrainID);
return;
}
}
//Close the connection
con.Close();
//Set the text for the command to insert data to the database connected to
insert.CommandText = "INSERT Train (id, departure, destination, type, intermediate, departure_time, departure_date, sleeperBerth, firstClass) " +
"VALUES ( #trainID , #departure, #destination, #type, #intermediate, #dep_time, #dep_date, #sleep, #first)";
//Parameters for adding values from the train object to the database
insert.Parameters.AddWithValue("#trainID", train.TrainID);
insert.Parameters.AddWithValue("#departure", train.Departure);
insert.Parameters.AddWithValue("#destination", train.Destination);
insert.Parameters.AddWithValue("#type", train.Type);
insert.Parameters.AddWithValue("#intermediate", intStops);
insert.Parameters.AddWithValue("#dep_time", train.DepartureTime);
insert.Parameters.AddWithValue("#dep_date", train.DepartureDay);
insert.Parameters.AddWithValue("#sleep", train.SleeperBerth);
insert.Parameters.AddWithValue("#first", train.FirstClass);
//Set the connection for the command for the insert sql connection
insert.Connection = con;
//Start the connection
con.Open();
//Execute the command specified
insert.ExecuteNonQuery();
//Close the connection
con.Close();
Sounds like you need to change your column id in the table train to an IDENTITY column, and let the database handle the ID assignment:
ALTER TABLE dbo.Train ALTER COLUMN id int IDENTITY(1,1); --data type guessed
Then, in your application, you don't need to generate a value for ID, nor do declare it in your INSERT statement (either in the list of columns to INSERT into or in your VALUES clause).

SqlCommand select all columns with a certain value

I have a SqlDataReader, which needs to read certain values out of my database. The SqlCommand which selects these values looks like this:
SqlCommand myCommand = new SqlCommand("SELECT * FROM dbo.Confronting_Value", valueConnection);
Each entry in the database consists of "Attacker", "Defender" and "Value". All 3 contain integer values.
For example
Attacker: "665", Defender: "443", Value: "3".
There may be multiple entries where the "Attacker" has the value "665".
Now, SELECT WHERE Attacker = 665 would be simple, but I have a variable Black.ID. I want to select all entries where the Attacker has the same value as Black.ID. How do I do that?
Not sure if I understand you correctly - but just adding a parameter to the query might work:
SqlCommand myCommand = new SqlCommand(#"SELECT *
FROM dbo.Confronting_Value
WHERE Attacker = #Value", valueConnection);
// add parameter and set its value to "Black.ID"
myCommand.Parameters.Add("#Value", SqlDbType.Int).Value = Black.ID;
and then from here on, run the code you already have. This will select all rows where Attacker has the same value as your Black.ID value.
Sorry, what is Black.ID? A variable in your code? A column of another table in the database?
In the first case add a Where clause to your command like this:
"SELECT * from dbo.Confronting_Value WHERE Attacker=" + Black.ID
or better
SqlCommand myCommand = new SqlCommand("SELECT * FROM dbo.Confronting_Value WHERE Attacker = #param1", valueConnection);
myCommand.Parameters.Add("#param1", SqlDbType.Int);
myCommand.Parameters["#param1"].Value = Black.ID;
Hope this can help you.

Database and DataSet are not synced regarding auto incrementing ID

I built a Database (Microsoft SqlServerCe.4.0) using Visual Studio and one table containing two fields:
id: int, primary key, not null, unique, no default value, identity
nom, we don't really care about this one
Then I built a DataSet containing this table as a DataTable and I have a DataAdapter like this :
marque_adapter = factory.CreateDataAdapter();
command = connection.CreateCommand();
command.CommandText = "SELECT * FROM " + DB_TABLE_MARQUE + ";";
marque_adapter.SelectCommand = command;
command = connection.CreateCommand();
command.CommandText = "UPDATE " + DB_TABLE_MARQUE + " SET nom = #nom WHERE id = #id;";
CreateAndAddParameterFromSource(command, "id", "id");
CreateAndAddParameterFromSource(command, "nom", "nom");
marque_adapter.UpdateCommand = command;
command = connection.CreateCommand();
command.CommandText = "DELETE " + DB_TABLE_MARQUE + " WHERE id = #id;";
CreateAndAddParameterFromSource(command, "id", "id");
marque_adapter.DeleteCommand = command;
command = connection.CreateCommand();
command.CommandText = "INSERT INTO " + DB_TABLE_MARQUE + " (nom) VALUES (#nom);";
CreateAndAddParameterFromSource(command, "nom", "nom");
marque_adapter.InsertCommand = command;
//...
data = new DataSet();
marque_adapter.Fill(data, DB_TABLE_MARQUE);
The problem arises when I try to insert a new row.
I do :
table.NewRow()
set the "nom" field
table.Rows.Add(newRow)
adapter.Update(dataSet, tableName)
If I don't do anything else, I have issues later when I try to get the ID of this row (I guess it will set it somewhere between the four instructions above).
I was expecting the DataTable to take care of generating one, but ...
So I tried remindind the DataTable to take care of the auto incrementing :
idColumn.Unique = true;
idColumn.AutoIncrement = true;
Now it works the first time, but when I run the program a second time, it starts counting from one again and I'm told that the ID should be unique. If I delete the database (the copy of the sdf file made by Visual), or if I delete the rows manually using Visual, it runs well the first time, and I get the same error after.
The problem really is when I try to save my DataSet, particularly when adding new rows (selecting, updating, deleting is fine).
Obviously I didn't get how to manage primary keys when the DataTable and the database are involved (the datatable alone is ok).
Particularly to sync the two ...
What did I miss ?
I am quite sure I have misunderstood something.
According to MSDN,
Bydefault, AcceptChanges is called implicitly after an update, and the original values in the row, which may have been AutoIncrement values assigned by ADO.NET, are lost.
So you need to create a strategy to merge the AutoIncremented value Either via ADO or getting back the incremented Id from Sql as output parameter and then merge the Identity column value as indicated in this MSDN Article.

Updating SQL table with the contents of a datatable

I am creating an application in WPF using C# where users populate a datagrid and the information is then stored in a DataTable called smb1. The following code works for inserting the data into the SQL database but when I modify the code for updating it does not work. Does anyone know how I can modify my code to allow Updates as there are no errors thrown when I run my application in Visual Studio. I must add that the Equipment column cannot be edited in the datagrid so the returned data is the same as the data taken from the database so that the updated rows will be matched to the equipment rows in the SQL database using the WHERE clause. Below is the original insertion code plus my attempt for updating the database.
Insert Code
SqlConnection con = new SqlConnection(MyConnectionString);
string SqlCmdText = "Insert into SHIFTLOG Values(#EQUIPMENT,#BATCHNO,#PRODUCTNO,#STATUS,#DATE,#PERIOD,#MACHINE)";
SqlCommand sc = new SqlCommand(SqlCmdText, con);
con.Open();
foreach (DataRow row in smb1.Rows)
{
sc.Parameters.Clear();
sc.Parameters.AddWithValue("#EQUIPMENT", row["EQUIPMENT"]);
sc.Parameters.AddWithValue("#BATCHNO", row["BATCHNO"]);
sc.Parameters.AddWithValue("#PRODUCTNO", row["PRODUCTNO"]);
sc.Parameters.AddWithValue("#STATUS", row["STATUS"]);
sc.Parameters.AddWithValue("#DATE", DateTime.Now.ToString("yyyy-MM-dd"));
sc.Parameters.AddWithValue("#PERIOD", DateTime.Now.ToString("tt"));
sc.Parameters.AddWithValue("#MACHINE", "SMB1");
sc.ExecuteNonQuery();
}
con.Close();
Attempt for Update Code
SqlConnection con = new SqlConnection(MyConnectionString);
string SqlCmdText = "UPDATE SHIFTLOG SET EQUIPMENT='#EQUIPMENT',BATCHNO='#BATCHNO',PRODUCTNO='#PRODUCTNO',STATUS='#STATUS',DATE='2013-09-12',PERIOD='#PERIOD',MACHINE='#MACHINE' WHERE EQUIPMENT='#EQUIPMENT'";
SqlCommand sc = new SqlCommand(SqlCmdText, con);
con.Open();
foreach (DataRow row in smb1.Rows)
{
sc.Parameters.Clear();
sc.Parameters.AddWithValue("#EQUIPMENT", row["EQUIPMENT"]);
sc.Parameters.AddWithValue("#BATCHNO", row["BATCHNO"]);
sc.Parameters.AddWithValue("#PRODUCTNO", row["PRODUCTNO"]);
sc.Parameters.AddWithValue("#STATUS", row["STATUS"]);
sc.Parameters.AddWithValue("#PERIOD", DateTime.Now.ToString("tt"));
sc.Parameters.AddWithValue("#MACHINE", row["MACHINE"]);
sc.ExecuteNonQuery();
}
con.Close();
Thanks for any help.
Remove the single quotes around the parameters.
string SqlCmdText = "UPDATE SHIFTLOG SET EQUIPMENT=#EQUIPMENT,BATCHNO=#BATCHNO,PRODUCTNO=#PRODUCTNO,STATUS=#STATUS,DATE='2013-09-12',PERIOD=#PERIOD,MACHINE=#MACHINE WHERE EQUIPMENT=#EQUIPMENT";
Also, I think the update section for EQUIPMENT=#EQUIPMENT is redundant, as the where clause will not be correct if it has changed. So you could use
string SqlCmdText = "UPDATE SHIFTLOG SET BATCHNO=#BATCHNO,PRODUCTNO=#PRODUCTNO,STATUS=#STATUS,DATE='2013-09-12',PERIOD=#PERIOD,MACHINE=#MACHINE WHERE EQUIPMENT=#EQUIPMENT";
remove the '' in all the parameters in your sql statement
"UPDATE SHIFTLOG SET BATCHNO=#BATCHNO,....... WHERE EQUIPMENT=#EQUIPMENT
if you use quotes all your parameters take as string values, not as SQL parameters
And also you need to use columns with [] like [DATE] if those are reserved keywords
How to deal with SQL column names that look like SQL keywords?

C#- Updating just updated column(s)

I have a web form. There are 20 fields that correspond to the columns in a database table. Let's say there's one record that has a BIRTHDATE column and I change its value from 13-July-2000 to 12-FEB-1985. But I don't touch the rest of the columns. Is there a way in C# to run an update statement like this:
UPDATE TABLE1 SET BIRHDATE=NEWVALUE WHERE ID=1111
instead of updating all the columns of the row like this:
UPDATE TABLE1 SET COLUMN1=NEWVALUE1, COLUMN2=NEWVALUE2,......,BIRTHDATE=NEWVALU
I think it would be a waste of resource. Am I wrong? I think DataAdapters are for this purpose but I'm not sure.
You can send a direct update statement to the Oracle Engine in this way.
using (OracleConnection cnn = new OracleConnection(connString))
using (OracleCommand cmd = new OracleCommand("UPDATE TABLE1 SET BIRHDATE=:NewDate WHERE ID=:ID", cnn))
{
cmd.Parameters.AddWithValue(":NewDate", YourDateTimeValue);
cmd.Parameters.AddWithValue(":ID", 111);
cnn.Open();
cmd.ExecuteNonQuery();
}
EDIT:
If you don't know which fields are changed (and don't want to use a ORM Tool) then you need to keep the original DataSource (a datatable, dataset?) used to populate initially your fields. Then update the related row and use a OracleDataAdapter.
using(OracleConnection cnn = new OracleConnection(connString))
using (OracleCommand cmd = new OracleCommand("SELECT * FROM TABLE1 WHERE 1=0", cnn))
{
OracleAdapter adp = new OracleDataAdapter();
adp.SelectCommand = cmd;
// The OracleDataAdapter will build the required string for the update command
// and will act on the rows inside the datatable who have the
// RowState = RowState.Changed Or Inserted Or Deleted
adp.Update(yourDataTable);
}
Keep in mind that this approach is inefficient because it requires two trip to the database. The first to discover your table structure, the second to update the row/s changed. Moreover, for the OracleDataAdapter to prepare the UpdateCommand/InsertCommand/DeleteCommand required, it needs a primary key in your table.
On the contrary, this is handy if you have many rows to update.
The last alternative (and probably the fastest) is a StoredProcedure, but in this case you need to go back to my first example and adapt the OracleCommand to use a StoredProcedure, (Add all fields as parameters, change CommandType to CommandType.StoredProcedure and change the text of the command to be the name of the StoredProcedure). Then the StoredProcedure will choose which fields need to be updated.

Categories

Resources