Deleting values from dataset - c#

I am trying to delete the data present in the dataset with following code:
stateflowDataSet dsobject = new stateflowDataSet();
stateflowDataSetTableAdapters.dbo_statetableTableAdapter statetableadapter = new stateflowDataSetTableAdapters.dbo_statetableTableAdapter();
statetableadapter.Fill(dsobject.dbo_statetable);
dsobject.dbo_statetable.Clear();
statetableadapter.Update(dsobject);
But after this line when use statetableadapter.Fill(dsobject.dbo_statetable); the data is still retained.
Is the way in which I am clearing the data right?
Is there any other problem with the code?

Removing DataRows from a DataTable does not mean that you'll delete them from your DBMS. The opposite is true, actually you're preventing them from being deleted even if you would have called DataRow.Delete() before.
The reason is: only DataRows that belong to a DataTable can be deleted by
DataAdapter.Update(table)
This will delete every row in the table with DataRowState=Deleted.
Therefor you need to use the Delete method.
foreach(DataRow row in dsobject.dbo_statetable.Rows)
{
row.Delete();
}
statetableadapter.Update(dsobject.dbo_statetable);
You could do it also in one batch which would be more efficient, therefor you need to set the DataAdapter's UpdateBatchSize to 0(unlimited).
Another way would to delete all rows is to use a simple SqlCommand with CommandText DELETE FROM Table:
using(var con = new SqlConnection(ConfigurationSettings.AppSettings["con"]))
using(var cmd = new SqlCommand())
{
cmd.CommandText = "DELETE FROM Table";
cmd.Connection = con;
con.Open();
int numberDeleted = cmd.ExecuteNonQuery(); // all rows deleted
}
Now you need to remove(not delete, what is the core of your question) the rows from the DataTable manually since you've also deleted them manually in the database:
dsobject.dbo_statetable.Clear();

Let me try re-wording Tims answer a little. I used DataSets alot when they were popular, and was confused with their 'magic'...
Dataset contains copy of the data from the database + your updates on the data since data is fetched from the database.
Update() method on the DataAdapter with your dataset isn't magic, it goes through your tables in the dataset, and in tables it scan rows. It will:
use DeleteCommand if row is marked for deletion
use UpdateCommand if row is marked for update
Former is the case when you delete a row with Delete() method, and later is the case when you update some cell in the row.
You will learn much about the process if you observe RowState property of each row in the dataset tables.

Related

C# OleDB Save Changes

OleDbConnection connection = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=\"C:\\Users\\User\\Desktop\\New Microsoft Access Database.accdb\"");
OleDbDataAdapter DataAdapter = new OleDbDataAdapter("SELECT *from pinakas", connection);
DataTable pinakas_Table = new DataTable();
DataAdapter.Fill(pinakas_Table);
MessageBox.Show(pinakas_Table.Rows[1]["Name"].ToString());
OK so this line displays the name "George" of my 1st Row of field
"Name".
pinakas_Table.Rows[1]["Name"] = "John";
Now this line sets field "Name" the value "John"
pinakas_Table.AcceptChanges();
DataAdapter.Fill(pinakas_Table);
MessageBox.Show(pinakas_Table.Rows[1]["Name"].ToString());
OK now my app displays the name "John" ! That means the DataTable "pinakas_Table" got the Change.
DataAdapter.Update(pinakas_Table);
But it's never saved to my Access database.
Updating Data Sources with DataAdapters states...
Calling AcceptChanges on the DataSet, DataTable, or DataRow will cause all Original values for a DataRow to be overwritten with the Current values for the DataRow. If the field values that identify the row as unique have been modified, after calling AcceptChanges the Original values will no longer match the values in the data source. AcceptChanges is called automatically for each row during a call to the Update method of a DataAdapter.
By calling pinakas_Table.AcceptChanges(); your modified row will be treated as if its data is unchanged from the database, so DataAdapter.Update(pinakas_Table); will see no action necessary for that row. Don't call AcceptChanges(). The Update method will call AcceptChanges() for you upon success.

Will UPDATE be called if I "change" a column value to what it already is?

I am trying to figure out if I need additional logic to avoid a useless call to my SQL db, or if SqlDataAdapter.Update() will do the right thing. If I have this code:
SqlConnection sqlconn = new SqlConnection(connectionString);
sqlconn.Open();
SqlDataAdapter da = new SqlDataAdapter(selectString, sqlconn);
SqlDataTable table = new SqlDataTable();
da.Fill(table);
new SqlCommandBuilder(da);
table.Rows[0][columnName] = 5; // Existing value is already 5
da.Update(table);
Will .Update() still call SQL's UPDATE for that row, or will it not, because no values for the row really changed?
It will call the update statement in SQL, because changing a value in DataSet and setting it to same again, will modify the RowState property.
DataAdapter.Update - MSDN
When an application calls the Update method, the DataAdapter
examines the RowState property, and executes the required INSERT,
UPDATE, or DELETE statements iteratively for each row, based on the
order of the indexes configured in the DataSet.
You can also confirm it using SQL Profiler.

C# - Concurrency access violation while updating MS Access table from DataGridView

I'm having some trouble updating Access tables from a DataGridView.
What's confusing me is that the code beblow works with one table and not with another, but they both have the exact same structure.
The tables
I have two tables with multiple (identical) fields, in which the primary key is a field called "Number" ; this field is Autoincrement, and indexed without duplicates, in both tables.
So I read about the lack of primary key as the origin of concurrency violation, but it doesn't seem to be the issue here.
The code
Here is the relevant part of my code, gathered together :
Initialization
BindingSource BS = new BindingSource();
DbDataAdapter adapter;
DataTable table = new DataTable();
OdbcCommand command = new OdbcCommand(query, odbcConnection);
OdbcDataAdapter adapter = new OdbcDataAdapter(command);
adapter.AcceptChangesDuringUpdate = true; // Attempt to fix the issue
adapter.AcceptChangesDuringFill = true; // same
DbCommandBuilder commandBuilder = new OdbcCommandBuilder(adapter);
dgv.DataSource = BS;
BS.DataSource = table;
adapter.Fill(table);
Saving the changes
OdbcCommandBuilder builder = new OdbcCommandBuilder((OdbcDataAdapter)adapter);
adapter.UpdateCommand = builder.GetUpdateCommand(); // Fix attempt
adapter.Update(table); // Where the exception is thrown
Considering my problem happens quite randomly depending on the database used, I think it's database related, but they got the same structure, and both are not in use (copied on my local drive) so I really don't have a clue what's happening.
Probably there are relationships defined to other tables, which might prevent an update of a certain field.
Also, a table might contain Indexes or Expressions for checking the validity of data, which prevent updating the table.
Have you checked these possibilities?
So I changed the corporate class to use OleDb instead of Odbc, worked like a charm !
The code remains exactly the same regarding the DataGridView, except OdbcCommand becomes OleDbCommand and OdbcDataAdapter becomes OleDbDataAdapter.

Reading DataSet

How do I read data from a DataSet in WPF? I have a train schedule table with just 2 columns and I want to be able to read the departure times and calculate when the next train is leaving. For example, the time now is 12:29 and my application should tell me that next train will depart at 12:33.
I already googled left and right. I'm on .NET 3.5.
DataSet resembles database. DataTable resembles database table, and DataRow resembles a record in a table. If you want to add filtering or sorting options, you then do so with a DataView object, and convert it back to a separate DataTable object.
If you're using database to store your data, then you first load a database table to a DataSet object in memory. You can load multiple database tables to one DataSet, and select specific table to read from the DataSet through DataTable object. Subsequently, you read a specific row of data from your DataTable through DataRow. Following codes demonstrate the steps:
SqlCeDataAdapter da = new SqlCeDataAdapter();
DataSet ds = new DataSet();
DataTable dt = new DataTable();
da.SelectCommand = new SqlCommand(#"SELECT * FROM FooTable", connString);
da.Fill(ds, "FooTable");
dt = ds.Tables["FooTable"];
foreach (DataRow dr in dt.Rows)
{
MessageBox.Show(dr["Column1"].ToString());
}
To read a specific cell in a row:
int rowNum // row number
string columnName = "DepartureTime"; // database table column name
dt.Rows[rowNum][columnName].ToString();
If ds is the DataSet, you can access the CustomerID column of the first row in the first table with something like:
DataRow dr = ds.Tables[0].Rows[0];
Console.WriteLine(dr["CustomerID"]);
If this is from a SQL Server datebase you could issue this kind of query...
Select Top 1 DepartureTime From TrainSchedule where DepartureTime >
GetUTCDate()
Order By DepartureTime ASC
GetDate() could also be used, not sure how dates are being stored.
I am not sure how the data is being stored and/or read.
TL;DR: - grab the datatable from the dataset and read from the rows property.
DataSet ds = new DataSet();
DataTable dt = new DataTable();
DataColumn col = new DataColumn("Id", typeof(int));
dt.Columns.Add(col);
dt.Rows.Add(new object[] { 1 });
ds.Tables.Add(dt);
var row = ds.Tables[0].Rows[0];
//access the ID column.
var id = (int) row.ItemArray[0];
A DataSet is a copy of data accessed from a database, but doesn't even require a database to use at all. It is preferred, though.
Note that if you are creating a new application, consider using an ORM, such as the Entity Framework or NHibernate, since DataSets are no longer preferred; however, they are still supported and as far as I can tell, are not going away any time soon.
If you are reading from standard dataset, then #KMC's answer is what you're looking for. The proper way to do this, though, is to create a Strongly-Typed DataSet and use that so you can take advantage of Intellisense. Assuming you are not using the Entity Framework, proceed.
If you don't already have a dedicated space for your data access layer, such as a project or an App_Data folder, I suggest you create one now. Otherwise, proceed as follows under your data project folder:
Add > Add New Item > DataSet. The file created will have an .xsd extension.
You'll then need to create a DataTable. Create a DataTable (click on the file, then right click on the design window - the file has an .xsd extension - and click Add > DataTable). Create some columns (Right click on the datatable you just created > Add > Column). Finally, you'll need a table adapter to access the data. You'll need to setup a connection to your database to access data referenced in the dataset.
After you are done, after successfully referencing the DataSet in your project (using statement), you can access the DataSet with intellisense. This makes it so much easier than untyped datasets.
When possible, use Strongly-Typed DataSets instead of untyped ones. Although it is more work to create, it ends up saving you lots of time later with intellisense. You could do something like:
MyStronglyTypedDataSet trainDataSet = new MyStronglyTypedDataSet();
DataAdapterForThisDataSet dataAdapter = new DataAdapterForThisDataSet();
//code to fill the dataset
//omitted - you'll have to either use the wizard to create data fill/retrieval
//methods or you'll use your own custom classes to fill the dataset.
if(trainDataSet.NextTrainDepartureTime > CurrentTime){
trainDataSet.QueueNextTrain = true; //assumes QueueNextTrain is in your Strongly-Typed dataset
}
else
//do some other work
The above example assumes that your Strongly-Typed DataSet has a column of type DateTime named NextTrainDepartureTime. Hope that helps!

Does DataSet occupy too much space?

If I wish to add some information to my SQL Server database, must I do it through a DataSet and a DataAdapter ?
The idea is that if my database has 1-2 million entries, isn't my memory going to be occupied unnecessary with the 1-2 mil rows in the DataSet considering that I want to add only one row? Is there an alternative ?
If you're only inserting a row, that needn't fetch anything into the DataSet/DataAdapter. You add the row, submit the changes, and the relevant INSERT command will be executed.
You could always create a plain old ADO.NET parametrized SqlCommand holding a simple SQL INSERT statement, and provide parameters, and load the data that way (nothing needs to be loaded, doesn't matter how many rows you already have - it will just work):
string insertStmt = "INSERT INTO dbo.YourTable(col1, col2, ...., colN) " +
"VALUES(#Value1, #Value2, ...., #ValueN)";
using(SqlConnection _con = new SqlConnection(-your-connection-string-here))
using(SqlCommand _cmdInsert = new SqlCommand(insertStmt, _con))
{
// define the parameters for your query
_cmdInsert.Parameters.Add("#Value1", SqlDbType.Int);
.......
// set the values
_cmdInsert.Parameters["#Value1"].Value = 4711;
.....
_con.Open();
int rowsInserted = _cmdInsert.ExecuteNonQuery();
_con.Close();
}
If you have multiple rows to insert, you could loop over e.g. a list of objects, set the values for our _cmdInsert for each object, and execute the _cmdInsert.ExecuteNonQuery() for each row.
Of course, if you use something like an ORM (NHibernate, Linq-to-SQL, Entity Framework), that work might get infinitely easier - just insert new objects into your collection and save them - the ORM will deal with all the nitty-gritty details (and basically do this code I showed above and execute it - more or less).

Categories