SqlCommandBuilder cannot handle SQLDataAdapter with Multiple SQL-Statement - c#

I'm working on a simple userclient (frontend) for a MS SQL Server database.
The database itself is pretty straight forward, there are eight tables without any foreign keys.
So far I managed to connect to the database and load all tables and data into a dataset.
I'm doing this by using a single string with multiple SQL-Statements (one for each table):
_dbconstrb = new SqlConnectionStringBuilder();
_dbconstrb.DataSource = ".\local";
_dbconstrb.InitialCatalog = "mydatabase";
string sql_str = "SELECT * FROM tbl1; SELECT * FROM tbl2; ..."
_dbda = new SqlDataAdapter(sql_str, _sqlcon);
_dbds = new DataSet();
_dbda.Fill(_dbds);
The dataset is bind to a bindingsource and this is set as datasource for a DataGridView. I'm using a simple ComboBox, where the user can select one of the eight database tables. Everytime the user makes any change on the combobox, the datamember of the bindingsource is set to selected table from the combobox. So far it works perfect.
Now the user will make any changes in the gridview data (add, delete or change records).
I would like to update the database by using the SQLCommandBulider and I tried this:
SqlCommandBuilder cmb = new SqlCommandBuilder(_dbda);
int updated = _dbda.Update(_dbds);
However this only works on the data of the first table (the table which comes first in the sql-string, in this case it is tbl1). It seems that all followed tables are not recognized by the DataAdapter. Do I really have to use eight DataAdapters (one for each table) to achieve this?
Solution:
Finally I managed this by adding eight DataApter. However, the Entity Framework looks very promising for such kind of datahandling. Again thanx for that point.

although your application might be simple not sure if loading the data from all the tables is good idea in terms of performance. I think using entity framework will help you http://www.asp.net/web-forms/overview/working-with-data-(entity-framework-tutorial)
and its really simple for what you are trying to do.

Related

C# SQLCe Inserting new rows with DataSet without loading the whole table?

I've a SQLCe database with a table. In the application there is a method which should only inserting new rows to this table.
I'm wondering what is the best practise for doing so. When working with a DataSet one has to load the whole table into it.
To me this seems like a big overkill, since I only want to insert new rows and therefore there is no need to fill the DataSet with the entire table.
On the other hand it also seems very ineffective to manually insert every single row with an explicit INSERT statement.
So in order to do a "batch"-INSERT one would go with a DataSet. Is there a possibility to work with a DataSet without filling the entire table, e.g. get only the schema of the table and then insert the rows to the DataSet?
Many thanks,
Juergen
Working with DataSet against a SQL Server Compact database is vey inefficient . you should use SqlCeResultSet or my wrapper lbrar, that allows you to do batch INSERTs very fast, based on a DataTable, a DataReader or even a List of objects. http://sqlcebulkcopy.codeplex.com

DataSet TableAdapter Fill Method

I have a DataSet with two TableAdapters (1 to many relationship) that was created using visual studio 2010's Configuration Wizard.
I make a call to an external source and populate a Dictionary with the results. These results should be all of the entries in the database. To synchronize the DB I don't want to just clear all of the tables and then repopulate them like dropping the tables and creating them with new data in sql.
Is there a clean way possibly using the TableAdapter.Fill() method or do I have to loop through the two tables row by row and decide if it stay or gets deleted and then add the new entries? What is the best approach to make the data that is in the dictionary be the only data in my two tables with the DataSet?
First Question: if it's the same DB why do you have 2 tables with the same information?
To the question at hand: that largley depend on the sizes. If the tables are not big then use a transaction, clear the table (DELETE * FROM TABLE or whatever) and write your data in there again.
If the tables are big on the other hand the question is: can you load all this into your dictionary?
Of course you have to ask yourself what happens to inconsistent data (another user/app changed the data while you had it in your dictionary).
If this takes to long you could remember what you did to the data - that means: flag the changed data and remember the deleted keys and new inserted rows and make your updates based on that.
Both can be achieved by remembering the Filled DataTable and use this as backing field or by implementing your own mechanisms.
In any way I would recommend think on the problem: do you really need the dictionary? Why not make queries against the database to get the data? Or only cache a part of the data for quick access?
PS: the update method on you DataAdapter will do all the work (changing the changed, removing the deleted and inserting the new datarows but it will update the DataTable/Set so this will only work once)
It could be that it is quicker to repopulate the entire table than to itterate through and decide what record go / stay. Could you not do the process of deciding if a records is deleteed via an sql statement ? (Delete from table where active = false) if you want them to stay in the database but not in the dataset (select * from table where active = true)
You could have a date field and select all records that have been added since the date you late 'pooled' the database (select * from table where active = true and date-added > #12:30#)

How can I select what columns come in from a DataSet into a DataTable?

Being new to working with Data, I hope I'm asking this properly. How can I select what columns come in from a DataSet into a DataTable? I know I can fill a DataTable by using...
DataTable table = dataSet1.Tables[0];
but this brings in all the columns. How can I fill a DataTable with only certain columns?
I'm using .NET 3.5, C#, and a SQL CE 3.5 single table database.
Thanks.
The DataTable is actually filled via a DataAdapter when the DataSet is created. Once you run your query, the columns in the DataTable are set. But, you can use a DataView to apply an additional filter and a column reduction to a DataTable, but the cost of querying the database and pulling data has already occurred, so you should consider making sure your query doesn't pull back more than you need. MSDN is a great resource.
Of course if you're just now learning this, it bears mentioning that while ADO.NET is important to know foundationally, you should be aware that there's a lot of momentum away from raw ADO.NET lately towards things like Entity Framework. While SQL will never die, nor should it, you're going to have to write a whole lot more plumbing code when using ADO.NET then you would with a nice ORM. Check out these posts for more info.
// Assumes that connection is a valid SqlConnection object.
string queryString = "SELECT CustomerID, CompanyName FROM dbo.Customers";
SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);
DataSet customers = new DataSet();
adapter.Fill(customers, "Customers");
DataTable table = customers.Tables[0];
Instead of "CustomerID, CompanyName" you can put the columns you want to select.
For further learning check this MSDN link.

C# DataAdapter and DataSet with multiple table

I have read from many places that it is possible to fill a DataSet with multiple tables using a DataAdapter. It also does not say whether a single Update call can update all the tables in the DataSet.
Can someone help me figure out how this can be done?
It seems like there isn't any ( i tried finding online ) examples on how to do it except for one that changes the SelectCommand on the DataAdapter before the second fill. But I feel this method defeats the purpose of the DataAdapter.
From what I figure, perhaps a single DataAdapter can only handle a single database table and Update only works on that table. Hence a multi-table DataSet will require respective DataAdapters call their Update to fully update the DataSet. Is this the case?
Finally, will foreign key relations and contraints hold in a DataSet (cascade delete, cascade update) automatically?
Maybe a link to an example or tutorial might help. Many thanks!
Yes it is true that, Single Adapter for single table.But
You can use Use table adapter manager for saving all at once, table adapter manager can have many individual adapters and you can call save for all. like, So no need to call save multiple time also it has other features too.
public void SaveWithManager()
{
DataSet1TableAdapters.TableAdapterManager mgr1 = new DataSet1TableAdapters.TableAdapterManager();
DataSet1TableAdapters.Table1TableAdapter taTbl1 = new DataSet1TableAdapters.Table1TableAdapter();
DataSet1TableAdapters.Table2TableAdapter taTbl2 = new DataSet1TableAdapters.Table2TableAdapter();
mgr1.Table1TableAdapter = taTbl1;
mgr1.Table2TableAdapter = taTbl2;
mgr1.UpdateOrder = DataSet1TableAdapters.TableAdapterManager.UpdateOrderOption.InsertUpdateDelete;
mgr1.UpdateAll(your dataset);
}
Finally cascade update delete is handled in dataset. You can view properties of relation and various options for cascade.(Typed dataset)

Strange Problem with updating Database from Dataset

Operations:
Delete in DataGridView selected row from Dataset:
FuDataSet.FuRow row = (FuDataSet.FuRow) ((DataRowView)FuBindingSource.Current).Row;
row.Delete();
To add a new Row I'm doing:
FuDataSet.FuRow row = FuDataSet.Fus.NewFuRow();
row.Someting = "Some initial Content";
row.SomethingElse = "More Initial Content";
...
FuDataSet.Fus.AddFuRow(row);
Saving user changes in current row in Dataset:
FuDataSet.FuRow row = (FuDataSet.FuRow) (((DataRowView) FuBindingSource.Current).Row);
row.Someting = someTextBox.text;
...
Save in Database:
Validate();
FuBindingSource.EndEdit();
FuTableAdapter.Update(FuDataSet.Fus); <-- Exception here
I'm using the standard DatagridView, Dataset, TableAdapter, BindingSource Scheme VS puts automaticly up after defining the database structure. There is only a single table involved and SQL Server compact 3.5 is used.
Now my problem is that I get a Concurrency Exception (DeletedRowInaccessibleException) each time I'm doing this (starting with an empty database):
Creating a new row, delete this row, save in Database, new row, save in database, delete this row, save in database <- Exception
I think that there is some synchroniszing problem between the database and the dataset.
If I'm reloading the databse after each save via FuTableAdapter.Fill(FuDataSet.Fus) the problem is gone. However, this cannot be the intention I think.
I hope someone can help me out and spot a failure in the design or explain me what may go wrong.
Thank you!
Does your table have an auto increment identity column as the primary key? If so it might not be updating the dataset table with the new value after the insert, so when you come to delete it, it cannot find the row in the database. That could explain why it works once you called the Fill() method.
You will need to somehow return the primary key on the insert so that the dataset table stays in sync with database. If you are using a store procedure to do the inserts, then primary key can be returned using an out parameter. Not sure what the best way is if you are using an SQL insert statement in the command, but you will then have to get the primary key back from the database table and assign it to the database table row.
Not sure if you are doing this after the saveing, but calling FuDataSet.AcceptChanges() will help the dataset track new changes after the database has been updated.
What you have listed there is correct. When a new row is created in the dataset table, it creates it's own ID. When you save to the database, the database table creates it's own ID as well, which in most cases will be different to the one in the dataset.
When you created the table adapter for that table, you had to supply a sql state to create the dataset table. On the advanced Options button, there is a checkbox called "Refresh the data table". Check that to have a sql statement added after the insert and update to retrieve the identity column.
If the checkbox is disabled then I am not sure what else you could, other than reload the data after each save, which will not be optimal.
Sorry I cannot be of more assistance. Best of luck

Categories