Unable to check for changed rows in a dataset - c#

I have a table within my program which stores information about messages and would like to detect when new information has been added to it. The reason I am doing this is beucause I would like to show the new data to the user only when there is new data instead of having to constantly get all the rows and display them.
The way I decided to do this was through the use of the dataSet.HasChanged() function which should essentially check the dataset for any new rows and a function called DataChanged returns dataSet.HasChanged() value.
However, the function I am using always returns false (even when there are changes)
Here is the function...
public bool DataChanged(string Table)
{
//This is the variable that will be returned
bool ChangesMade;
//Create the adapter
OleDbDataAdapter adapter = new OleDbDataAdapter(Table, connector);
//Clear the current data in the dataset
dataSet.Clear();
//Open the connection and fill the dataset
connector.Open();
adapter.Fill(dataSet, "TableData1");
connector.Close();
return ChangesMade = dataSet.HasChanges();
}
Changes for some reason are never detected and therefore this function always returns false even after I add a new record to the dataset.
An alternative method that provides the functionality explained in paragraph one would be very helpful and the fixing of my current method ever more so.

Here is an easy way to do this.
Make sure a Timestamp/Rowversion column exists for each table you wish to track changes to.
Return the current database Timestamp to your calling program as part of your data result set (DataSet in this case). For example, add the following query to your result set.
SELECT ##DBTS;
Use this returned value the next time you run your query with the following added to the existing WHERE clause(s) as appropriate.
...
AND (#LastRowversionValue IS NULL
OR TableName.RowversionColumn > #LastRowversionValue)
...
Pass NULL for the #LastRowversionValue the first time the query is ran to get the process started.
Any rows that are inserted/updated into the table(s) since the last time you retrieved data, will have an Rowversion greater than the one you stored from the last execution.

Related

C# DataGridViewRow - is new or updated row

I have DataGridView where I am showing data read from database:
DataSet ds = new DataSet();
sqlDa.Fill(ds);
dgView.DataSource = ds.Tables[0]
After adding all of the rows in the UI, I need to to SQL UPDATE of rows that previously read from database, and do INSERT for new rows by clicking Save button (I don't save rows one by one when adding, just all of them when I click the Save button):
foreach (DataGridViewRow dgvRow in dgView.Rows)
{
// do insert for new rows, and update for existing ones from database
}
How can I know what rows are newly added and what are not? Can I add some type of attribute to every row that is read from database so that can I know that they need to be updated?
How can I know what rows are newly added and what are not?
You don't need to; the datatable the DGV is showing is already tracking this. If you make a SqlDataAdapter and plug a SqlCommandBuilder into it see the example code in the docs so that it gains queries in its InsertCommand/UpdateCommand/DeleteCommand properties (or you can put these commands in yourself, but there isn't much point given that a command builder can make them automatically) then you just say:
theDataAdapter.Update(theDataTable);
If you didn't save it anywhere else you can get it from the DataSource of the DGV:
theDataAdapter.Update(dgView.DataSource as DataTable);
Ny the way, the word "Update" here is nothing to do with an update query; Microsoft should have called it SaveChanges. It runs all kinds of modification query (I/U/D) not just UPDATE
If you really want to know, and have a burning desire to reinvent this wheel, you can check a DataRow's RowState property, and it will tell you if it's Added, Modified or Deleted, so you can fire the appropriate query (but genuinely you'd be reimplementing functionality that a SqlDataAdapter already has built in)
All this said, you might not be aware that you can make your life massively easier by:
Add a new DataSet type of file to your project (like you would add a class). Open it
Right-click in the surface of it, choose add TableAdapter
Design your connection string in (once)
Enter your query as a "select that produces rows" like SELECT * FROM SomeTable WHERE ID = Id (it's advisable to use a where clause that selects on the ID; you can add more queries later to do other things, like SELECT * FROM SomeTable WHERE SomeColumn LIKE #someValue but for now selecting on ID gives you a base query to use that is handy for loading related data). You can also use existing or new stored procs if you want
Give it a sensible name pair like FillById, GetDataById - FillBy fills an existing table, Get gets a new one
Finish
You'll now have objects available in your code that are wrappers data adapters and datatables - same functionality but more nicely strongly typed
e.g. you can fill your grid with:
var ta = new SomeTableAdapter();
dgView.DataSource = ta.GetDataByFirstName("John%"); //does select * from table where firstname like 'john%' into a datatable
The datatables are strongly typed, so you don't access them like this:
//no
foreach(DataRow row in someTable.Rows){
if((row["someColumn"] as string) == "hello" && row.IsNull("otherColumn"))
row["otherColumn"] = "goodbye";
}
You have named properties:
//yes
foreach(var row in someTable){
if((row.SomeColumn == "hello" && row.IsOtherColumnNull())
row.OtherColumn = "goodbye";
}
Much nicer. LINQ works on them too, without AsEnumerable or Cast and endless casting the values.
It's not magic; VS writes boatloads of code behind the scenes for you - check in the YourDataSet.Designer.cs file - hundreds of SqlCommands, fully parameterized, for all the table operations (Select/Insert/Update/Delete), all base don typing a SELECT command into a tool pane. It's quite nice to use really, even all these years later.
Oh, but the designer doesn't work very nicely in net core. They're really lagging behind on fixing up the bugs that netcore brings (other priorities)

c# Delete row from DataTable and use TableAdapter.Update and .Fill

Why is the DataTable not empty even after it has been cleared?
In the beginning I cleared the the "PasswoerterDataTable". But afte updating and filling it back it is not empty anymore. Did I misunderstood the usage of the .fill and .update commands? How do I correct my mistake so that the "PasswoerterDataTable" is empty in the end?
PasswoerterDataTable.Rows.Clear();
// DataTable is now empty
PasswoerterTableAdapter.Update(PasswoerterDataTable);
PasswoerterTableAdapter.Fill(PasswoerterDataTable);
// DataTable is not empty anymore. Why?
I know that it does not make sense to use .update and .fill after each other but I am currently working on a PasswordManager and I want to delete Passwords. These deleted Passwords should not appaer when the program is closed and started again but I need to use .fill after Startup to get the Passwords which haven't been deleted. But after I used .fill the Passwords reappear.
The Fill method exists to read data from a database table and put it inside an in memory DataTable object. I think you are misunderstanding the work of the Clear method and the Update method.
The Clear method removes all rows from the in memory datatable but doesn't change anything on the database table. The Update method looks at the rows present in your PasswoerterDataTable and checks their RowState property. If it finds something to update then a command is executed to reflect the changes back to the database.
But you have cleared the rows from PasswoerterDataTable so Update has nothing to update and your database table is left unchanged. The following Fill reloads everything.
If you want Update to execute delete commands on the database you need to set the RowState of each row to Deleted. And you can do this with
foreach(DataRow row in PasswoerterDataTable.Rows)
row.Delete(); // This doesn't remove the row, but sets its RowState to Deleted
// Now the adapter knows what to do...
PasswoerterTableAdapter.Update();
Of course this is totally unnecessary and you can simply write a single Command to act directly on your database to TRUNCATE your table
SqlCommand cmd = new SqlCommand("TRUNCATE TABLE PasswoerterTable", connection);
cmd.ExecuteNonQuery();
PasswoerterDataTable.Rows.Clear();
// No need to call Fill again.

How to get the Original Row and the Modified Row of DataRowView using DataRowViewVersion

I have a datatable that is filled from a database. I load a bindingsource with that table.
Sub LoadData()
Dim bsTemp As BindingSource = New BindingSource
bsTemp.DataSource = dtTemp
End Sub
I then have other code programmatically editing the values in the datatable. I NEVER call AcceptChanges() ..let me be clear NEVER.
I do call bsTem.EndEdit() and I also call that on my dtTemp.Row(x).EndEdit() Whenever I make a change to it.
So now all I want to do is compare the two rows (I know I can do this with a for each column but I am not wanting to do that.)
I would like to know how to make this work:
Dim modview As New DataView(dtTemp.Copy, "", "Id", DataViewRowState.ModifiedCurrent)
Dim origView As New DataView(dtTemp.Copy, "", "Id", DataViewRowState.ModifiedOriginal)
So I can then perform something like this:
Dim rowComparer As DataRowComparer(Of DataRow) = DataRowComparer.Default
IsEqual = rowComparer.Equals(origRow.Row, modRow.Row)
When I do this both views show the Modified data, one of them should only show me the Original unmodified Row.
I know I can do this [C# version]:
SomeDataRow[0, DataRowVersion.Original] //by index
SomeDataRow["ColumnName", DataRowVersion.Original]
But again tis works on a column by column basis - me being the iterator - and I see no reason to do that when the DataView supposedly has this built in .
So what could I be doing wrong that I do not see the original version .
The New DataView(..) does not determine which rows to copy, it only says what the state of the rows after they are in the view will have. Your first parameter says which rows dtTemp.Copy.
Since the copy method of a datatable is a copy of all rows, you might want to use something like the select method, which allows you to filter based on state.
dtTemp.Select("","",ModifiedOriginal)
EDIT:
There must be an issue with getting it that way. According to the example given from MSDN, it should work if you use the DataView.RowStateFilter. I tested it and it did work. I think the key is that the DataView controls what you see. If you look at the raw data through the DataRow, it is always current.

Insert a DataRow inside a table

I have a function that returns a typed DataRow object and now I would insert this DataRow in a given table. As far as I know I could do this using TableAdapter in two ways: TableAdapter.Update and TableAdapter.Insert.
Both ways seems pretty simple to use but, first way could even delete row from the table (essentially my DataSet will be "serialized" on my DB table) and since this table is really the application's critical part I would avoid any chance of data deletion, so I would prefear Insert method.
The problem seems to be that Insert method doesn't accept a DataRow object as it's parameter (unlike Update), so I need to manually insert each parameters. Alas I have at least 80 parameters so this is a really really headache operation. What can I do now?
The update method does allow you to insert,update or delete changes in the tableAdapter. MSDN: 'Use the TableAdapter.Update method when your application uses datasets to store data. The Update method sends all changes (updates, inserts, and deletes) to the database'. Although Insert is ment for usage if you want more control for you data inserts but does not allow you to pass a datarow instead Parameters must be used. See complete reference on MSDN: http://msdn.microsoft.com/en-us/library/ms233812(v=vs.110).aspx
Code example of Update method usage.
// Create a new row.
NorthwindDataSet.RegionRow newRegionRow;
newRegionRow = northwindDataSet.Region.NewRegionRow();
newRegionRow.RegionID = 5;
newRegionRow.RegionDescription = "NorthWestern";
// Add the row to the Region table
this.northwindDataSet.Region.Rows.Add(newRegionRow);
// Save the new row to the database
this.regionTableAdapter.Update(this.northwindDataSet.Region);
Code example Insert:
NorthwindDataSetTableAdapters.RegionTableAdapter regionTableAdapter =
new NorthwindDataSetTableAdapters.RegionTableAdapter();
regionTableAdapter.Insert(5, "NorthWestern");

how to check whether the value is inserted or not

Am using DataSetTableAdapters for inserting data.how can i check whether the value is inserted or not..I want to show the error or success message after completion of inserting..
My partial code is here:
DataSet5TableAdapters.sp_inempleaveTableAdapter TA = new DataSet5TableAdapters.sp_inempleaveTableAdapter();
TA.GetData(ddlperiod.SelectedItem.Text, lblid.Text, name, leave_value);
How can i display the success message (or) error message after the above step...
Remember that the GetData() method returns a table adapter class that inherits from the DataTable. Thanks to this, GetData() gives you access to regular operations performed on a table.
So if you compare the row counts before or after or even if the result is larger than 0
e.g. GetData().Rows.Count > 0 you can raise an event or show a MessageBox depending on your type of applicatoin.
Also please check out this link Table Adapters and DataSets

Categories

Resources