SQL CE & Dataset - Row does not exist - c#

I'm (new to and) working with a SQL CE database that will later be connected to a project where we send and receive information to a device over a SerialPort. This database will store information about every part of the communication. I'm a little stuck when it comes to updating a Dataset and committing this updated data to the database.
data = new DataSet();
adapter = new SqlCeDataAdapter("SELECT * FROM " + [table_name])
builder = new SqlCeCommandBuilder(adapter);
adapter.Fill(data, [table_name]);
data.Tables[table_name].Rows[identity_value][a_column] = a_column_value;
adapter.Update(data, [table_name]);
Before I run this method I'm ensuring that I have a record in the table at identity value 1. However I'm getting a There is no row at position 1 IndexOutOfRangeException before I call the adapter.Update(). I'm assuming that I've misunderstood how to use and update a Dataset. Any advice?
I've tried looking into the Dataset prior to trying to update the row however the debugger doesn't seem to let me peer into the Dataset, is there a way to do this?

try this:
var rows = data.Tables[table_name].Select(String.Format("[Id] = {0}",identity_value));
if (rows.Length == 1)
{
rows[0][a_column] = a_column_value;
}
you are interpreting wrong the property Rows
data.Tables[table_name].Rows[ROWINDEX][COLUMNINDEX]
ROWINDEX is the array index not the identity
A suggestion:
if you have to use DataSet then load table schema info too with SqlCeDataAdapter.FillSchema:
adapter.FillSchema(data.Tables[table_name], SchemaType.Mapped);
adapter.Fill(data, [table_name]); this loads only the data:
Then if you have at least one column designated as a primary key column in the DataTable you can get the row with DataRowCollection.Find Method:
DataRow foundRow = data.Tables[table_name].Rows.Find(identity_value);

Related

DataAdapter_RowUpdated Event's row changes aren't reflected in DataSet and DataTable

My situation involves batch updates to individual tables in an SQLite database through ADO.NET objects. I use the DataAdapter.Update() method to push the changes which works well:
DataTable changes = dataset.Tables[table].GetChanges();
if (changes == null) return 0;
SQLiteCommandBuilder scb = new SQLiteCommandBuilder(adapter);
scb.ConflictOption = ConflictOption.CompareRowVersion;
int cnt = adapter.Update(changes);
return cnt;
However each time a record is inserted I also want the local DataSet tables to reflect with the newly inserted row id. For this I use the adapter_RowUpdated event :
static void adapter_RowUpdated(object sender,
System.Data.Common.RowUpdatedEventArgs e)
{
if (e.StatementType == StatementType.Insert)
{
SQLiteCommand cmd = new SQLiteCommand("select last_insert_rowid();", conn);
e.Row["id"] = cmd.ExecuteScalar();
}
}
The above fetches last_insert_rowid() because I'm able to see it when I debug by putting a breakpoint. However, the assignment statement to e.Row["id"] isn't working. The id change isn't reflected in my original DataSet and DataTable objects. For example when I test the following value (N refers to the specific row index), it still has a DBNull value. What is going wrong here? How can I ensure that the specific row which just got inserted is updated with its corresponding id field value?
dataset.Tables["projects"].row[N]["id"];
After a little experimenting, I found the solution to this myself.
As strange as it may sound but it looks like adapter.Update() requires a dataset along with the actual table name in order for this to work. I was passing the table object (DataTable.GetChanges()) so far which did the job of updating the database but failed only in this particular scenario. The moment I did that, the inserted id started reflecting in rows all over the dataset!
//int cnt = adapter.Update(changes); // doesn't work
int cnt = adapter.Update(dataset, tableName); // works perfectly!
edit
Lo and Behold! It even works when I just pass the table like this instead of entire dataset. It was only causing problem when I was just passing the changes table (got from dataset.Tables[tableName].GetChanges()).
int cnt = adapter.Update(dataset.Tables[tableName]); // works perfectly!

How to adjust the order of data in Dataset by Date asc? , C#

I am assigning data to a Dataset manually from the data of another Dataset, in which two conditions are met one when there is data from another Dataset where the date field matches the rows with this data, otherwise I add them as a new row. This is perfect.
The problem is that when you finish assigning the data to the Dataset, the data that shows first are the ones that are updated with the first condition.
I need the data to be sorted by Date either dd\MM\yyyy or yyyy/MM/dd without taking into account the hours, and regardless of whether it was updated or added, but to order it by Date of ASC mode.
//foreach (DataRow dr in ds.Tables[0].Rows)
foreach (DataRow dr in ds.Tables[0].AsEnumerable().OrderBy(x=>x.Field<DateTime>("date").Date).ToList())
{
var row=dataset_manually.Tables[0].AsEnumerable().Where(x=> x.Field<DateTime>("date").Date == ((DateTime)dr["date"]).Date).FirstOrDefault();
if (row!=null)
{
//Update the data
row["entryToTurn"]=(DateTime)dr["entryToTurn"];
row["departureToTurn"]=(DateTime)dr["departureToTurn"];
row["turn"]=dr["turn"].ToString();
}
else
{
//Add new rows
var row2= dataset_manually.Tables[0].NewRow();
row2["entryToTurn"] = dr["entryToTurn"];
row2["departureToTurn"] = dr["departureToTurn"];
row2["turn"] = dr["turn"].ToString();
dataset_manually.Tables[0].Rows.Add(fila2);
}
}
For some reason the OrderBy in the foreach does not work. adds the data but does not order it. foreach (DataRow dr in ds.Tables[0].AsEnumerable().OrderBy(x=>x.Field<DateTime>("date").Date).ToList())
I tried this but it did not work:
dataset_manually.Tables[0].DefaultView.Sort = "date asc";
And I can not do it like this:
datagridview1.Sort(datagridview1.Columns[0], ListSortDirection.Ascending);
Because this only shows the data ordered in the DataGridView but when using the Dataset in another side the data is not sorted and the positions of the values in the grid are not the same things in the Dataset.
Desired output:
Note: The data is NOT assigned by the index, it must be assigned where the date field matches
Environment: Visual Studio 2010 (WindowsForms C#) & .NET NetFramework 4
Your code is not working because you first sort your data set and then you add new rows to it (so after everything)
Solution for this is slow if you have a lot of rows inside data set so I AM RECOMMENDING TO DO NOT DO THIS BUT SORT DATA AFTER LOADING IT INTO CODE.
Solution to this problem could be:
Load Data from DB into dataGridView
Get dataSource from dataGridView as DataTable
Add new data to DataTable
Sort DataTable
Save sorted data
Sorting could be done with:
DataView dv = data.DefaultView;
dv.Sort = "PrimaryColumn asc" //desc for descending
data = dv.ToTable();

Get Inserted Row after .Net Dataset Row Added

I have a .Net dataset and am adding a row to a table. This works and the record is saved to the database. How do I get the updated version of my row after the insert. Or, alternatively, how do I know the ID of the item that was added (so that I can then use it in a subsequent child table insert.
MyDataSet.ProjectRow r = dsMyDataSet.Projects.AddProjectRow(txtTitle.Text);
m_daProjects.Update(dsMyDataSet.Projects);
// What is the ID of the new item here?
If the column is an identity column you can find the new ID's in the inserted rows.
You: "thanks. which object maintains a list of inserted rows?"
You can use DataTable.GetChanges(DataRowState.Added) to get a DataTable with all DataRows which are going to be added. You need to use it before AcceptChanges was called. If i remember correctly TableAdapter.Update calls AcceptChanges at the end. Then you need to use it before m_daProjects.Update(dsMyDataSet.Projects):
DataTable addedRows = ds.modModel.GetChanges(DataRowState.Added);
MyDataSet.ProjectRow r = dsMyDataSet.Projects.AddProjectRow(txtTitle.Text);
m_daProjects.Update(dsMyDataSet.Projects);
now addedRows contains all DataRows with the new identity value in each row
foreach(DataRow addedRow in addedRows.Rows)
Console.WriteLine("New ID: {0}", addedRow.Field<int>("IdColumn"));
Update: However, in your case it's simpler. You have already the single row that you want to insert. So you dont need to call DataTable.GetChanges at all.
You can see the new identity value in the (typed DataRow) ProjectRow r after Update.
Thanks to Tim Schmelter. In the link he posted there's a reference to an article on Beth Massi's blog with a complete walkthrough of the solution. It worked for me.
http://blogs.msdn.com/bethmassi/archive/2009/05/14/using-tableadapters-to-insert-related-data-into-an-ms-access-database.aspx
The basic steps are:
1) Add RowUpdated event handler on the strongly typed table adapter. This event handler issues a new OleDBCommand to the database to retrieve ##Identity and then assigns the integer to the member column of the table.
public void _adapter_RowUpdated(dynamic sender, System.Data.OleDb.OleDbRowUpdatedEventArgs e)
{
HMUI.Classes.AccessIDHelper.SetPrimaryKey(this.Connection, e);
}
public static void SetPrimaryKey(OleDbConnection trans, OleDbRowUpdatedEventArgs e)
{
if (e.Status == System.Data.UpdateStatus.Continue && e.StatementType == System.Data.StatementType.Insert)
{
if (pk != null)
{
OleDbCommand cmdGetIdentity = new OleDbCommand("SELECT ##IDENTITY", trans);
// Execute the post-update query to fetch new ##Identity
e.Row.Table.Columns[pk(0)] = Convert.ToInt32(cmdGetIdentity.ExecuteScalar());
e.Row.AcceptChanges();
}
}
}
2) In the constructor of the form using the dataset and table adapter I attach the function in step 1 to the RowUpdated event on the table adapter's internal data adapter.
// Event to handle inserted records and retrieve the primary key ID
m_daDataSources.Adapter.RowUpdated += new System.Data.OleDb.OleDbRowUpdatedEventHandler(m_daDataSources._adapter_RowUpdated);

Appending DataRow to DataTable filled from DataAdapter, clears all records

I have a DataGridView that has a DataTable bound to it, populated from PostgreSQL database with Npgsql .NET data provider library.
Populating records works, but when I want to append just a single records to already existing DataTable, previous records vanish:
NpgsqlDataAdapter npDataAdapterSingle = new NpgsqlDataAdapter("SELECT * from \"Weight\" ORDER BY id DESC LIMIT 1", this.npConnection);
DataTable tmpTable = new DataTable("tmpTable");
npDataAdapterSingle.Fill(tmpTable);
DSWeight.WeightRow row = this.dSWeight.Weight.NewWeightRow();
row.ItemArray = tmpTable.Rows[0].ItemArray;
this.dSWeight.Weight.Rows.InsertAt(row, 0); //Prepend, but i also tried this.dsWeight.Weight.Rows.Add(row);
If I select all records, without LIMIT'ing, then it works as expected. But I thought - why would i need to query the database all over again if I already have those records? That's why I want to LIMIT.
Maybe there is another solution, because I manually add new records to database and query them to add them to datatable, not the way it is supposed to be: add new records to datatable and them to database. I do it this way because I want the database to manage the id and timestamp fields and have datagridview to have these fields populated.
What am I missing?
Am not sure about the data type of DSWeight.WeightRow and the scope of 'this' object since I get to see only a portion of the code and not the full method. This should probably work for you. please have a try.
NpgsqlDataAdapter npDataAdapterSingle = new NpgsqlDataAdapter("SELECT * from \"Weight\" ORDER BY id DESC LIMIT 1", this.npConnection);
DataTable tmpTable = new DataTable("tmpTable");
npDataAdapterSingle.Fill(tmpTable);
row = tmpTable.NewRow();
foreach (DataColumn col in tmpTable.Columns)
row[col.ColumnName] = tmpTable.Rows[0][col.ColumnName];
tmpTable.Rows.Add(row, 0);

Update Datatable and DatagridView with database Changes by Timer

Scenario : i have a database table that is being updated frequently by some services.
I have a c# Winforms Application that load this table in a datagridview by binding a datatable as Datasource, then i whant to add a Timer that every 10 seconds update a the content of a datatable with the last changes in the database table ...
I don't need to update a database with the datatable changes, but i need to update datatable with the last changes in the database table, that is the inverse of the usually....
Is there a way to do that ? What is the best way ?
i've tried with this code :
private void ServiceTimer_Tick(object state)
{
OdbcConnection oCon = new OdbcConnection();
oCon.ConnectionString = ConnectionStrings;
OdbcDataAdapter dp = new OdbcDataAdapter("SELECT * FROM table", oCon);
dsProva.Tables.Clear();
dp.Fill(dsProva,"table");
dataGridViewMessaggi.DataSource = dsProva.Tables["table"];
dataGridViewMessaggi.Refresh();
}
But every Timer Tick i lost the selection in DatagridView and Current Row ....
Is There a better solution ?
Before updating the data grid, you will need to store all the current selections you are interested in and then restore them once the new data binding has completed.
The CurrentRow, you can get from the BindingContext. For example
int lastRow = BindingContext[dsProva.Tables["table"]].Position;
Then to restore the current row after rebinding the DGV
BindingContext[dsProva.Tables["table"]].Position = lastRow
Of course this will only ensure the current row is pointing to the same row index, which if your data has changed enough might not be the same data row as before.
If you want to have the same row interms of data selected, you can can use the key of the row and loop through the data and once you find the index of the row that matches the previous selection you can set the binding context to that index.

Categories