I would like to insert into a database from SQL Server with a BindingSource in Windows Forms and VB.
Right now I have a DataTable with its DataTableAdapter in 'Details' mode and a bunch of TextBoxs (and other Controls, but that isn't the issue) whose Text attributes are bound to my BindingSource.
If I fill the TableAdapter XDataTableAdapter.Fill(XDataSet.XTable)
those TextBoxs receive the data from the first entry, and BindingSource has every row from the db and every column value, so BindingSource and the adapters work.
Instead of modifying the existing entries I would like to insert a new one with its contents as those linked in the various TextBoxs.
I was told I should then use XBindingSource.AddNew()
and lastly, once I am certain of the data in the TextBoxs XDataTableAdapter.Update(XDataSet.XTable)
.
The problem is, before I execute AddNew my BindingSource can read what is being written. But once I reach AddNew, the count of BindingSource increments in 1, but the Items of its current row are empty, regardless of the content of the TextBoxs.
So the issue is, after BindingSource.AddNew, the rows from the db contain its values correctly, but the current new one has them empty, without reading from the bindingsources of the textboxes. Is there any instruction for BindingSource to execute so it knows that the new row should read the textboxs?
So when, I reach the Update instruction, the new row is empty so it doesn't change anything.
My question is, how can I tell BindingSource that the new current row is what is being written in the TextBoxs.
I just wanted to insert into my database straight from the controls bindings, without having to link each one manually.
I'll correct a few misconceptions if I may; hopefully it'll help you understand what's going on:
Right now I have a DataTable with its DataTableAdapter in 'Details' mode and a bunch of TextBoxs (and other Controls, but that isn't the issue) whose Text attributes are bound to my BindingSource.
You have a TableAdapter - a generic name for the type of thing VS generates for you when you use this method of accessing a database. Be sure to call them TableAdapters, as that's what we know them by, and they're distinct from DataAdapters, which are a more basic thing for accessing databases. People might be confused as to which you mean if you call it a DataTableAdapter
TableAdapters don't have a "Details" mode. "Details" refers to something you did in the Data Sources window - you changed from datagrid to details and then dragged a node representing a datatable onto the form, and a bunch of textboxes etc appeared, along with a tableadapter, dataset, bindingsource, bindingnavigator and maybe a tableadaptermanager. At this point you could do nothing else except run the program and it will be able to save new data. "Details" means "create a bunch of textboxes rather than a datagrid" and is a function of the datasources window only
If I fill the TableAdapter XDataTableAdapter.Fill(XDataSet.XTable) those TextBoxs receive the data from the first entry, and BindingSource has every row from the db and every column value, so BindingSource and the adapters work.
Again, a slight terminology tweak: You don't fill a TableAdapter, a TableAdapter is a device that fills a datatable. The datatable that it fills lives inside a dataset. The bindingsource is bound (connected) to the datatable. The datatable holds a cache of local data downloaded from the database. Textboxes are bound to the bindingsource. Because a textbox can only show one record at a time, the bindingsource maintains knowledge of what is the "current" record. The bindingnavigator (a toolbar) moves the bindingsource's current pointer, which causes the textboxes to change values. You use the textboxes to change the values or add new ones. This causes the bindingsource to transmit changes through to the underlying datatable, affecting whatever row it considers to be the "current" row. At some point you save the changed datatable back to the db. The underlying datatable rows change from Unchanged (the state they have when downloaded) to Modified. This is how the tableadapter knows to run the SQL UPDATE query - it looks at the state of the row
Instead of modifying the existing entries I would like to insert a new one with its contents as those linked in the various TextBoxs. I was told I should then use XBindingSource.AddNew() and lastly, once I am certain of the data in the TextBoxs XDataTableAdapter.Update(XDataSet.XTable).
You can indeed do this. The bindingnavigator has a +
button on it that does this, or you can write some other code that calls AddNew()
on the bindingsource. When you call AddNew the bindingsource makes a new data row but it doesn't add anything to the datatable immediately. When you tell a bindingsource to AddNew, it will switch to pointing its current at the new item, all the textboxes go blank, and you can type the new details into them. These details will go into the new temporary row but remember that that row is not a part of the underlying datatable yet
The problem is, before I execute AddNew my BindingSource can read what is being written. But once I reach AddNew, the count of BindingSource increments in 1, but the Items of its current row are empty, regardless of the content of the TextBoxs.
It's not a problem, it's by design. It's only the same as opening Word and writing a document - it's not saved on your hard disk yet, it's just in memory. You need to do something to commit it to hard disk, just like you need to do something to a bindingsource to make it commit the new item into the underlying data store (the datatable)
To make it commit you need to do something like: navigating to another record, or calling EndEdit()
on the bindingsource. At this point it adds the row to the underlying table and this new row has a RowState of Added - this means that when the tableadapter runs its Update (which should really be called Save) it will use the built in SQL INSERT query to save the row; because it's Added/new/needs inserting into the DB
So the issue is, after BindingSource.AddNew, the rows from the db contain its values correctly, but the current new one has them empty, without reading from the bindingsources of the textboxes. Is there any instruction for BindingSource to execute so it knows that the new row should read the textboxs?
I think you're doing things in the wrong order. You're supposed to AddNew, then fill in the text boxes with the new data, then do something like navigate away from the new data, or hit save or some other button that does a Validate()/EndEdit() on the form/the bindingsource. The committing of the new row happens upon EndEdit() of the bindingsource; that puts the row into the table but it still isn't saved to the db at this point. To save, one must call tableadapter.Update(theTable)
It might seem a bit odd, but again, think of it like MS Word. You could open an existing document, then you can do Ctrl+N for a new document, then you write the document. The new document isn't saved to disk yet.
In tableadapter terms the process is the same: You could download an existing database table, then you can do AddNew for a new row, then you write the new row details. The new row isn't saved to database yet.