I'am trying to update database after row has been deleted from dataset like this:
SqlCommand mySelectCommand = new SqlCommand("select * from NameDB", c);
SqlDataAdapter mySqlDataAdapter = new SqlDataAdapter(mySelectCommand);
TheNewDataSet ds = new TheNewDataSet();
mySqlDataAdapter.Fill(ds, "NameDB");
DataRow[] FilteredRow = ds.Tables["NameDB"].Select("PName like '" + listBox2.SelectedValue.ToString() + "'");
foreach (DataRow drr in FilteredRow)
{
ds.Tables["NameDB"].Rows.Remove(drr);
}
mySqlDataAdapter.Update(ds, "NameDB");
c.Close();
And nothing happened to database, rows not deleted. According to debugger rows filtered correctly and deleted from DataSet normally. Where is mistake?
Ok, first - it is not the dataset doing updates. NEVER EVER. It is the Adapter. The DataSet does not talk to the database.
But: you dont delete the rows, you - kill them (rows.remove).
http://msdn.microsoft.com/en-us/library/feh3ed13(v=vs.80).aspx
You should not use REMOVE but DELETE, which keeps the row with a status to delete it. THe way you do it you remove it, so the adapter never sees it. With ".Delete" the adpater sees the row as deleted, so it can act upon it.
Looks like you are missing insert/update/delete commands on the sqldataadapter?
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldataadapter.updatecommand.aspx
I ran into a similar problem today at work, so I would like to answer what I understood, so that this could be of some help in the future for others as well as myself.
From what I understood today, .Remove will take the rows of visually from the grid, but would not mark them as the rows to be deleted when you do AcceptChanges to save the changes to the database. As TomTom mentioned, you should use .Delete instead, which will mark those rows as the one's that needs to be deleted when persisting. If you debug your program and see the dataset in visualizer(?), you could see the difference. If I am correct, .Delete will have the rows marked with exclamation, and .Remove, I think just removes.
Related
I have timer-function. It handles data from sql database every N time (it's doesn't matter actually what time). The subsequent algorithm does not work. Or I don't know how to make it work.
I put data into Dataset.
const string query = "SELECT id FROM SomeTable LIMIT 100";
await using var cmd = new MySqlCommand(query, connection);
var sqlAdapter = new MySqlDataAdapter(cmd);
sqlAdapter.TableMappings.Add("Table", "SomeTable");
sqlAdapter.Fill(_mapping);
_mapping.AcceptChanges();
Where _mapping is dataset.
If this is the first filling of the dataset, then just fill it.
If this is not the first filling, then try to update the data in it. I tried to use sqlAdapter.Update(_mapping). But it doesn't update any data Or I cant get updated data. I tried fill it again and check _mapping.hasChanges(DataRowState.Modified | DataRowState.Added))
But it hasn't any changes.
So how can I fill dataset and catch changed or added rows while I get data from Database?
Or may be I need to use another things like dataTable or something else?
i have datagridview that connect to my database (access)
if i stay on any cell and change the value, a see that the value is changed
but when i make refresh i see that the value is back to the original value.
how i can update this cell (without sql query)
i bind dataset to datagridview like this:
dsView = new DataSet();
adp = new OleDbDataAdapter("SELECT * FROM Items", Conn);
adp.Fill(dsView, "Items");
this.dataGridView1.DataSource = dsView.Tables["Items"].DefaultView;
adp.Dispose();
please, i must find how to do it.....
thank's in advance
If your datagridview is connected to the database and you do not want to use SQL, i can suppose it is bound to a datasource. If you performed that through the Visual Studio Designer there should be a TableAdapter (if automatically generated, probably called YOURTABLENAMETableAdapter) and a BindingSource (if automatically generated, probably called YOURTABLENAMEBidingSource).
To update your database you will have to call BindingSource.EndEdit() and then TableAdapter.Update(). After you have done this, you can refresh your data.
EDIT
Now that you have provided better information i can give you a better answer.
In my previous answer, I assumed that you created everything with the designer because you didn't want to use SQL to make the update. Obviously i was wrong.
To achieve what you are looking for, you should use the OleDbCommandBuilder Class which, given a SELECT command, automatically generates simple editing command (insert/update/delete) for your table.
here is an example using your code:
dsView = new DataSet();
adp = new OleDbDataAdapter("SELECT * FROM Items", Conn);
OleDbCommandBuilder cb = new OleDbCommandBuilder(adp);
adp.Fill(dsView, "Items");
this.dataGridView1.DataSource = dsView.Tables["Items"].DefaultView;
//adp.Dispose(); You should dispose you adp only when it is not loger needed (eg: after performing the update)
Now, after you perfomed your changes to the data you can call
adp.Update(dsView, "Items");
I'm having some trouble getting my DataSet to work.
I have a MDB-Database in the background and created a DataSet out of it. Now I created a new method that lets me create a new user in the table.
But when I call it, nothing happens. No exceptions, no errors and I even get "1" returned as number of affected rows. But when I look in the database, no user was added.
I have the feeling that I miss to somehow tell the DataSet that I want to operate the Database itself rather than just the internal DataSet... How can I achieve this?
// DataSet1 uses the connection to the Database.mdb
// Created by the Designer
// The Users table has 3 columns, id, name and password
DataSet1 set = new DataSet1();
UsersTableAdapter adap = new UsersTableAdapter();
DataSet1.UsersRow row = set.Users.AddUsersRow("asd", "asd");
int count = adap.Insert("das", "das");
MessageBox.Show(row.RowState.ToString() + ": " + count.ToString());
count = adap.Update(set.Users);
set.AcceptChanges();
MessageBox.Show(row.RowState.ToString() + ": " + count.ToString());
// The Messagebox shows: "Added: 1"
// The second one: "Unchanged: 1"
MessageBox.Show(set.Users.Rows.Count.ToString());
// Returns "2"...
Not knowing too much about your code, try reading this how to from MSDN:
http://msdn.microsoft.com/en-us/library/ms233812(v=VS.80).aspx
Update: with data sets, what would normally happen (assuming the data set has been populated) is rows would be added, edited, or deleted in code. These rows would have a corresponding RowState signifying them as added, edited, deleted, or unmodified. During the .Update the associated table adapter, complete with associated insert/update/delete commands, will iterate the rows and execute the command on a given row depending on the row's state. When the rows have been iterated, .AcceptChanges is called, reverting the row state's to default.
If you call AcceptChanges before updating, then nothing will happen. The RowState of each row will be lost so the .Update will not have the required information it needs to perform the update to the database. If you have custom code for wrapping it all in a transaction, then you need to make sure you commit the transaction.
In your example, you seem to imply you are using the table adapter and not the data set itself. I would advise against this - the table adapters usually place methods on the tables in a data set that you should use.
Update 2: the code looks OK to me, though you don't need to call Insert on the adapter, or AcceptChanges after the update (the latter is done automatically). This leads me to believe there is a bug in your insert command SQL - try extracting the SQL used by the command and run it manually against the database.
Update 3: the following code works fine for me:
static void Main(string[] args)
{
db1DataSet set = new db1DataSet();
set.Users.AddUsersRow("asd", "asd");
foreach (DataRow row in set.Users.Rows)
{
object foo = row.RowState; // Confirm row state in debugger.
}
UsersTableAdapter adap = new UsersTableAdapter();
adap.Update(set.Users);
Console.Read();
}
Scenario
I have a c# winforms application with a gridview.
The gridview datasource is populated by a dataset.
The contents of this dataset get updated every few seconds, and there are not always the same number of items in the dataset etc.
The dataset actually gets populated (or needs to get populated) by multiple other datasets being passed in one at a time.These datasets update at completely random times that cannot be controlled.
The Issue
Since essentially the GridView dataset is being "CONTINUALLY UPDATED" - At the time of an update(The point that a new dataset with the latest information in it needs to be merged with the existing GridView DataSource), I need to take a copy of the current dataset populating the gridview, compare it to the incoming data from the other dataset and update ONLY the data that is new.
So Far
I've tried a series of different methods but I can't seem to get this to work. I either end up with the dataset just being added to continually with duplicates of slightly different data, or the rows randomly get deleted (I tried using a merge all then delete approach which only works occasionally).
Any ideas how I can get around this!?
At the moment the gridview just updates itself to show the latest incoming dataset without the previous dataset merged into it.....
CODE - This randomly deletes the rows even though it does at some points display all data
//If the existing GridView dataset contains any rows that
//exist in the incoming latest dataset (matched on the two unique fields
//of the dataset), then remove that row from the existing GridView dataset
for (int i = 0; i < existingPriceResultsDTCopyForCompare.Rows.Count; i++)
{
foreach (DataRow incomingRow in incomingDS.Tables[0].Rows)
{
string incomingDate = incomingRow["Date"].ToString();
DataRow currentRow = existingPriceResultsDTCopyForCompare.Rows[i];
if ((currentRow["CCY"].ToString().Contains(incomingCcy))
&& (currentRow["Date"].ToString().Contains(incomingDate)))
{
existingPriceResultsDT.Rows.RemoveAt(i);
}
}
}
//Then merge the existing GridView dataset (Minus the old data that
//matches the data from the incoming Dataset with the latest information),
//With the brand new incoming data.
incomingDS.Merge(existingPriceResultsDT);
EDIT -
I'm beginning to wonder if the incoming dataset keeps being overwritten by the next incoming dataset before the iteration has time to complete. So I'm guessing I need to lock the incoming DataSet?
Have you tried something similar
DataSet ds1 = new DataSet();
DataSet ds2 = new DataSet();
ds1.Merge(ds2);
DataSet ds3 = ds1.GetChanges();
As per your Objects
DataSet existingPriceResultsDT = new DataSet();
DataSet incomingDS = new DataSet();
incomingDS.Merge(existingPriceResultsDT);
existingPriceResultsDT = incomingDS.GetChanges();
You might want to look into the Microsoft Sync Framework. This sounds like a perfect scenario for it. This video is a good introduction. You can also download the tutorials here.
That nested for-loop stuff is a big-O nightmare. You definitely want to get out of the business of looping through those rows - lots of unnecessary compares.
It looks like you've got a couple of columns there that you are comparing each time - "CCY" and "Date". Have you considered using them as the primary key for the table? If that makes sense for your scenario, you can make things considerably more efficient.
You could consider doing something like this:
Determine which columns are primary keys - it appears here that CCY and Date are for you.
DataColumn[] keys = new DataColumn[2];
keys[0] = dataTable.column["CCY"];
keys[1] = dataTable.column["Date"];
dataTable.PrimaryKey = keys;
Then when you read in a new DataSet - however you do that, call Merge on it like so:
dataSet.Merge(newDataSet, false, MissingSchemaAction.Add);
Assumption here is that dataTable is the Tables[0] of dataSet.
This, at least for my quick test program, will merge the two DataSets and update the rows that changed and add any new ones.
And, I just had my DataGridView set up like so:
dataGridView1.DataSource = dataSet.Tables[0];
Seemed to update the view well enough for my test program.
Hope that helps.
I'm attempting to pull some data from a SQLite database so that I can populate a GridView in my GUI: here is the code that returns the DataTable:
DataTable table = new DataTable();
SQLiteDataAdapter adapter = new SQLiteDataAdapter(this.command.CommandText, this.connection);
adapter.Fill(table);
return table;
For some reason after calling adapter.Fill, the DataTable is still not populated with anything. So far I've verified that the command text is correct and that the connection contains the correct connection string. Both are used successfully in other parts of the application. No exceptions seem to be thrown... Is there any place else I should be looking for trouble? Am I using the API incorrectly?
Thanks!
This looks like correct usage.
One thing to check -- after the fill you say the datatable is not populated. Were you just checking Rows.Count? What about columns? If the Fill creates columns to match your SELECT statement, but there aren't any rows, then you know the code is working but there's a problem with either your query, or you're not hitting the same database you think you are.
Is there a constructor that lets you just pass in the command directly?