How to Insert Into SQL Server Using BindingSource - sql-server

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.

Related

How to preserve BindingSource EndEdit() revert changes?

I have simple details-edit form.
Data is read from Database. DataAdapter fills DataTable and Dataset
I have created BindingSource (bs) and bound all controls to bs
Before saving to database bs.EndEdit() is called (in order to reflect all changed controls values in datasource)
All works great, except scenario when there are errors caused by constraints (eg column cant be NULL, or unique value is expected).
In this case bs.EndEdit() causes exception (what is OK) but also revert all changes (what is not OK to me...). So I end up in the situation when Im loosing all data entered by user (giving no chance to fix problem)
I must be doing something wrong - can someone please advise how to properly handle such scenarios?
In order for this to work, the BindingSource's underlying data object must implement IEditableObject:
Ref MSDN #1:
When the EndEdit method is called, all pending changes are applied to
the underlying data source.
This method has no effect unless the objects contained by the data
source implement the IEditableObject interface.
Ref MSDN #2:
IEditableObject Interface Definition Namespace: System.ComponentModel
Assembly: System.ComponentModel.dll Provides functionality to commit
or rollback changes to an object that is used as a data source.
Cheers

ListView binding data set (no database)

Let say, I have ListView, how do I bind/connect it with another data-set?
For example: Screenshot
A new row added, new default extra data added
A specific row is selected, display extra data
All row selected, display similar data and display multiple value if not same
All row selected, change a extra data, all selected row apply new data
A specific row deleted, the extra data also gets deleted.
this not connected with database, just simple data in the memory
A standard .NET ListView doesn't support data binding.
You will need to switch to DataGrid (which has its own problems) or a data bindable version of ListView, like ObjectListView.

WPF Data gird row selection change event from selection change event

I'm looking for a workaround to an issue I've noticed in a project that I'm working on. I have a datagrid bound to a list of a class I've created. Whenever a user types in a stock symbol in this datagrid I have the roweditending event set to pull in some information to populate the other fields in the datagrid.
This generally works fine, however I've noticed that the event doesn't fire in some instances. I'm going to try to explain this the best I can... upon data entry if I enter information into a cell and then click another row on the datagrid - focus doesn't shift to the new row but shifts to the row containing the cell I was just entering data into from that cell, then if I select another row or input element the row edit ending event doesn't appear to fire and as such my code to populate the rest of the row doesn't execute.
Everything else is fine, and it's a pretty subtle issue, only one path of input to make it happen, but I was wondering if anyone had run into this or found a work-around?
I've been looking at the selection change event, but I need to be able to grab the row that was selected. In the row edit ending event I use
Dim NewTrade As Trade = e.Row.DataContext
to get the instance of my class that the row represents and to add the additional fields.
I'm not sure I see a way to get the row and it's datacontext for the row I just shifted from using the SelectionChangedEventArgs.
Any ideas for a workaround?

Totals Row in a DataGridView

I am developing a winform application application. I wanted to show sum of columns in last row of each column. This row must always be visible.
At moment I am thinking about adding another datagridview just beneath my datagridview with records, and would show the sum in that bottom datagridview.
If there is a better way to achieve this task?
No, need of adding another datagridview
Solution 1: Please refer to this solution
Solution 2: If the above link is not exactly what you want then,
You can try to manually add last, summary, row in which you can display information that you need. For example, you can try to do the following:
Read data from database and fill System.Data.DataTable
Add one column to the newly created DataTable – that column might be set
to true for the last, summary, row
Programmatically add one extra row that contains suitable summary data
Do the data binding to DataGridView control
Using appropriate event, bold or otherwise graphically distinct summary
row (row that have extra column value
set to true)
You can do it in the same way as you suggest, like placing a datagridview for displaying the sum. you can also handle the Horizontal Scroll with this, if there are more columns.
Another method is there in this link
Another way you can Add Rows to your datasource itself to display the sum.
Even if this question is quite old-ish I'd like to propose an extension to Niraj Doshis answer. His answer holds true for a data bound DataGridView. I recently had the problem to calculate the summary in a user-editable DataGridView, whose solution differs in the details. Anyway It's quite straight-forward too. I am writing my functions on a higher abstraction level, which outlines the workflow, but elides the implementation details.
First of all you'll have to initialize the DataGridView, see
private void InitializeDataGridView()
{
SetColumnTypes();
AddEmptyRow();
AddSummaryRow();
}
I set DataGridView.AllowUsersToAddRows to false for the new row would be located beneath the summary row. Hence I am adding an empty row, which the user may fill with his data. The summary row is set to ReadOnly since we do not want our user to edit it. Whenever a CellEndEdit is raised I am updating the DataGridView with the following method
private void UpdateDataGridView()
{
RemoveSummaryRow();
RemoveEmptyRows();
UpdateRowNumbers();
AddEmptyRow();
AddSummaryRow();
}
First I remove the summary and all empty rows (you'll have to take care. If you are trying to delete the row you just edited an exception will be thrown. I've not yet figured out how to do this, but I just made up the solution. I'll amend when I came up with the solution.) Afterwards I'm setting a running number in each of the rows. This is not really required, but a detail of my implementation. At the end I add an empty row again which the user may use to add further data and then calculate and add the summary row.
As I said before this is not yet a ready-made solution, but rather I concept which works but with some quirks and bugs.

How do you get a Microsoft Access form to refresh a computed column?

I have a Microsoft Access form that is bound to a linked SQL Server table that has a computed column. I have a control bound to the computed column.
I already realize that the computed field cannot be refreshed until AFTER a record is saved. Beyond that, what is the best way to refresh that textbox that is bound to the computed column after save.
I would prefer not to do a me.requery (a requery of the whole recordset).
Is there a way to JUST refresh that one field?
EDITED FOR CLARITY: There are actually a few strategies to consider.
Form.Refresh() will refresh your Form's recordsource capturing modifications and deletions to existing records and will stay positioned on the current record. However, you would not see any NEW records that were added since you opened your form.
Form.Requery() will re-run the Form's recordsource query. You will see all the Form.Refresh() changes AND it will show you any new records. On the UI, Form.Requery() repositions to the first record.
Form.Control.Requery() is similar to Form.Refresh() in that you will not change record position or see NEW records. It will update your control, assuming the control is based on a query/table.
You'll need to be sure that the triggering event involves a database update. There can be cases where the control's AfterUpdate() precedes database I/O, which wouldn't help you.
Thanks guys. Here it what worked.
In the Form AfterUpdate event I did a Me.ControlName.Requery. This was perfect as it did not do a complete form refresh or requery.
I just experimented with different event/method combinations until I got the best result.
Thanks for the input.
Seth
2016 (related) Answer: In Access 2016, I have a control that is a calculated field based on values in 4 other bound textboxes. I set the Control Source for the calculated field to be =gsngCalculatePaymentAmount([txtInterestRate],[txtLengthOfLoanInYears],[txtSalePrice],[txtMoneyDown]).
But I needed the value to be refreshed whenever ANY of the values for any of those 4 textboxes changed. Had difficulty in making the calculated value refresh. SOLUTION: In the AfterUpdate event in EACH of the 4 textboxes whose value was being used for the calculated field, I simply did the following:
Dim v1 As Variant
v1 = Me.txtMyCalculatedTextbox
Simply referencing the value of the calculated field resolved it!
Rex
Have you tried .Refresh for either the underlying recordset, or for the bound control? I would expect it to work for a Jet/ACE back end, but the interaction with different database server back ends is going to be non-predictable.
There might also be an interaction with you ODBC refresh interval, but I would expect a manual refresh in code to take care of that.
Where to call it is another issue -- I would assume the appropriate place would be in the AfterUpdate events of the controls bound to the fields the calculation is based on. But you might have to save the record for the server-side calculation to happen -- Refresh alone might or might not do the trick. I know with Jet/ACE data sources a Refresh saves the record, but I don't know for certain if it behaves the same way with ODBC data sources.
I did it this way (the control source of txtTextBox is an SQL Server field whose value is computed):
On Error Goto ErrorHandler
'After saving data when I wanted to see the updated value of computed field
txtTextBox = txtTextBox & ""
ErrorHandler: If err.Number = -2147352567 Then 'The data has been changed.
Resume Next
else
msgbox err.description
end if

Resources