How to add data to MS Access database with VB.NET? - vb.net

I know this would be really simple but I don't know what is wrong with my code. I have tried several times.
I have two things, Username & Password on my db table. I want to add data to a DataGridView and save it to my db table. I use 2 buttons ADD & SAVE.
Database Table
ID Username Password
1 Zain 12345
2 Admin root
VB.NET Code (as explained in https://www.youtube.com/watch?v=XRVBpTFa3To)
Public Class edmin
Private Sub edmin_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'UserInfoDataSet1.Users' table. You can move, or remove it, as needed.
Me.UsersTableAdapter.Fill(Me.UserInfoDataSet1.Users)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
UsersBindingSource.AddNew()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Try
UsersBindingSource.EndEdit()
UsersTableAdapter.Update(UserInfoDataSet1.Users)
MessageBox.Show("Saved")
Catch ex As Exception
MessageBox.Show("error")
End Try
End Sub
End Class

When you add a data file, e.g. MDB or ACCDB, to your project, it becomes a source file. When you run your project in the debugger, your app does not connect to that database. When you build, that source data file is copied to the output folder, along with your EXE, and it's that copy that you connect to at run time. If you go looking in the source file for any data added during testing, of course you won't find it.
This makes perfect sense when you think about it. When it comes time to deploy your application, do you really want to have to spend time cleaning up the database to put it into a state suitable for distribution? By testing against a copy, you keep the source database in pristine condition. When you build a Release version of your app, the clean source database is copied into the Release output folder with the EXE and your users get that clean copy.
Now, when you add the database to your project, its Copy to Output Directory property is set to Copy always by default. That means a new copy is made every time your project is built. If you run your project and make changes to the database, then stop the debugger, make changes to the code and then run the project again, the project is rebuilt and a new copy of the database made, thus your changes disappear. If you run the project twice without making any changes to the code then it won't be built the second time so the changes in your working database will not be overwritten.
What you should do - and what I think Microsoft should have done by default - is change that Copy to Output Directory property to Copy if newer. That way, even if your project gets built, a new copy of the database will not be created unless you have made a change to the source database. That will allow you to keep the same test data in your working database as long as you want. When you do want to start afresh, simply delete the data file from the output folder manually or change the Copy to Output Directory for a single build.
Microsoft caution against this because the source file can change even if you don't make a change to the data or schema it contains. Simply opening the file can affect it and prompt a new copy to overwrite your working directory. If a new copy would be created every time though, I say big whoop. I've rarely seen a data file update when I didn't intend it to. You can read here for more information.
Now, with regards to IDs, your DataTable is going to create a temporary ID when you add a new row. That ID can be used to identify the row, even to related child rows, as long as you use the data in your app without committing it to the database. When you do commit the change, a permanent ID is generated by the database.
Often you don't need that ID right then and there because you won't be using the data right then and there. You won't be using the data again without retrieving it again, in which case you will retrieve the final ID with it. Sometimes though, you do want to retrieve the final ID immediately. One scenario where this is essential is where you're saving a parent record and one or more child records. When you save the parent record, you need to get the final ID from the database and put it back into your DataTable so that the foreign key values in the child row(s) can be updated before you save the child row(s). If you save the child row(s) without doing that then you'll violate the foreign key constraint in the database and an exception will be thrown.
Some data providers, e.g. SqlClient for SQL Server, support multiple SQL statements per command. In this case, you can simply add a SELECT statement after your INSERT statement and the new ID will get retrieved back into your DataTable with no extra code. Unfortunately, the Jet and ACE OLE DB providers don't support multiple SQL statements per command. As a result, you have to write some code explicitly retrieve the new ID when a record is inserted. Here's a quick code example of how you can do that with a typed DataSet:
''' <summary>
''' Handles the RowUpdated event of the parent adapter.
''' </summary>
''' <param name="sender">
''' The adapter that saved the row.
''' </param>
''' <param name="e">
''' The data for the event.
''' </param>
''' <remarks>
''' This event handler is used to retrieve an auto-generated ID from the database after a row is inserted and update the corresponding row in the local data set.
''' </remarks>
Private Sub parentAdapter_RowUpdated(sender As Object, e As OleDbRowUpdatedEventArgs)
'We are only interested in new records.
If e.StatementType = StatementType.Insert Then
'Get the last ID auto-generated by the database.
Dim lastAutoNumber = Me.parentAdapter.GetLastAutoNumber().Value
'Update the ID of the local row.
DirectCast(e.Row, ParentChildDataSet.ParentRow).ParentID = lastAutoNumber
End If
End Sub
In that case, GetLastAutoNumber is a query that I added to the table adapter in the DataSet designer. It is a scalar query that simply contains the following SQL:
SELECT ##IDENTITY
You can find the complete example here.

Related

How to resolve issue with DataSet and Database connection in Visual Studio?

I am using VB.NET with an MS Access database. There are two tables with a relationship with each other.
I followed the following to make a database connection with the dataset and binding Source.
Under Data Source add new Data Source
Database as a data source type
Dataset as a database model >>
Chosen Data connection
Under the database object, I selected Table (s) which want for the purpose like customer table also clicked on views
Then finish.
Now at Data source, selected Dataset then Table of Customers and drag details and data grid view to the form and add buttons for adding, deleting updating the records.
Now run the application.
After running the application, But it's not viewing, adding, updating, and deleting records from/to the database.
Code for adding a record to the database
CustomersBindingSource.AddNew()
Code for updating a record to the database
CustomersBindingSource.EndEdit()
CustomersTableAdapter.Update(SrsbdbDataSet.Customers)
Code for deleting a record from the database
CustomersBindingSource.RemoveCurrent()
I also edited a connection string from the app.config file to check the connection string issue but not useful for the issue.
Please let me know where I'm doing wrong.
CustomersBindingSource.AddNew()
This doesn't add a record to the access database, it adds a record to the BindingSource's list, which (when EndEdit is called on the BindingSource) is pushed into the YourDataSetName.Customers DataTable as a new DataRow - if you were to look at all the rows in YourDataSetName.Customers you'd see that there are some (downloaded from the db probably, when you started the app) and they have a DataRowState of Unchanged, and then there is the new one you added, with a DataRowState of Added
Nothing has been saved to the DB yet. This data is only in the dataset's datatable, which is a client side representation of a database table. It is not a database table in and of itself. It can certainly have more or fewer columns and of different types, than the database table. It's just temporary storage for database data; you download some, add some, change some, delete some, maybe save it etc. The relevant DataRow tracks all these things you do to its data and notes whether it is Added/Modified/Deleted/Unchanged etc
The TableAdapter is the thing that pushes the data back and forth between the DataTable and the database
You call CustomersTableAdapter.Update() when you want to save the data to the DB. Naming it Update was a crap idea on Microsoft's behalf, because it leads people to think it only performs SQL UPDATE queries; if it had been called SaveChanges (and later it was; EF uses SaveChanges) it would be more clear.. You just have to remember that one - "Update means Save"
So you call Update(datatable or dataset here) and pass in your DataTable with all its modified/deleted/added rows. The TableAdapter scans the whole DataTable row by row looking at the DataRowState of each row. If it's Added, then the TableAdapter will call its built in INSERT SQL query to save the row. If it's Modified, SQL UPDATE is performed. Deleted state causes an SQL DELETE. A datarow knows the original data that was downloaded and the data as it is now; this is sometimes vital in working out if someone else saved this row in the time we had it, so we can avoid overwriting their changes with ours
At the end of this process, the data has been saved, the rowstates have all been set from whatever they were, to Unchanged (because the data in the db is now the same, the row data no longer needs saving).
Think of that part of the process as being like the little * that appears on a text editor tab, when you edit the file - a datarow in state Added/Modified/Deleted has unsaved changes that need to be saved. After saving, the state goes back to Unchanged. Did I mention that TableAdapter.Update should have been called Save?
All in, the process for saving would be to ask the editing control to EndEdit() then ask the relevant bindingsource to EndEdit - this ensures we have a datatable with all changes committed and ready to save, and then call the tableadapter.Update. Probably the control the user was typing in will commit its edits when it loses focus, as the user clicks the save button.. But calling endedit makes sure. If you're uncertain, create a new form, drop a DataGridView on it out of the Data Sources window and take a look how the Save button is wired up - from memory it does a Validate, couple of EndEdits and a UpdateAll (TableAdapterManager, manages TableAdapters, calls Update on them in the right order to make sure that parent rows save before child rows)
If you started making more modifications, the row states would change again but just as before, the thing that commits the changes to the DB is TableAdapter.Update() regardless what kind of change you made
The final thing to watch out for here is that Access is a file based database. Probably you have your project in e.g.:
C:\projects\accesswhatever\
And you had your access db on e.g. your desktop:
c:\users\you\desktop\access.mdb
When you connected the access db into things, VS presented a long and wordy dialog (that no-one reads ;) ) where it basically says "i'll put the db in your project, and I'll make it copy out to the bin folder when you build".
So you click OK without considering the ramifications of it and you build. Your disk now looks like:
C:\users\you\desktop\access.mdb 'call it DB X
C:\projects\accesswhatever\access.mdb 'call it DB Y
C:\projects\accesswhatever\bin\debug\access.mdb 'call it DB Z
Your running program will save data in the last one, DB Z. Every time you build (which might happen every time you click play, if you make code changes), visual studio will delete Z and copy Y to Z.
You're now really confused; your code says it's saving. You're looking in either DB X on your desktop, or DB Y in your project base, and wondering where the heck is this data?
It's in DB Z, in the bin\debug folder, next to your app.exe - just remember that every time you build, VS wipes your changed database and replaces it with a clean one from way back when. If you want to change this, click the DB in solution explorer and set "Copy To Output" from "Copy Always" to "Copy If Newer". Now it'll only copy whenever you make a schema change, so.. Add a new table and then VS will wipe your nicely curated test db with a new one.. But it's more like OK because the new empty DB at least has that extra table that your program will crash without :)
An alternative is to add the new record directly in DataGridView and use new OleDbDataAdapter for the connection.
Remove 'CustomersBindingSource.AddNew()', and edit record in DataGridView:
Code in 'Update Record' button.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim connstring = "your connection string"
Dim adapter As OleDbDataAdapter = New OleDbDataAdapter("select * from Customer", connstring)
Dim builder As OleDbCommandBuilder = New OleDbCommandBuilder(adapter)
builder.QuotePrefix = "["
builder.QuoteSuffix = "]"
adapter.Update(CustomerDataSet.Customer)
End Sub

How can I update 2 different Access databases from one dataset?

I currently have a datagridview that is data bound to a local Access database. The form that holds the datagridview allow users to add or remove records and then update the database.
This all works like a charm. The part where I am having trouble is after the first database is successfully updated, I then want to update the master database as well that is located in a different directory.
Basically I create a new connection and then change the local connection (original) to the new database. I then update the database and close the connection. When I step through the code I can see that the new database is getting opened properly yet nothing happens when the Update command executes. I close the connection, watch the new database close on screen, and then exit the app.
When I open the new database, nothing has changed.
Is using a dataset from one database to update a different, yet identical database possible? I don't get any errors when running, just a database that opens but does not update.
Private Sub UpdateMasterDatabase()
'Create a connection to the Master database and open it
Dim masterConnection As New OleDb.OleDbConnection(MASTER_DATABASE_CONNECTION_STRING & MASTER_DATABASE_FILEPATH & MASTER_DATABASE_NAME)
masterConnection.Open()
'Change the connection from the Local database to the Master database
TeamProjectsTableAdapter.Connection = masterConnection
'Update the Master database
Me.TeamProjectsTableAdapter.Update(Me.DataSetDVM.TeamProjects)
'Close the connection
masterConnection.Close()
masterConnection = Nothing
End Sub

updating a database using a table adapter and data table

I am currently working on a VB program connected to an Access database. I have fill a data table using a query and data adapter. At a later stage in the program, i want to go through and make permanent changes to the database using the adapter and table. I tried this:
For Each row As DataRow In db.DBDT.Rows
row("fldsentda") = "Y"
row("flddasenddate") = Date.Today
Next row
'db.DBDT.AcceptChanges()
db.DBDA.Update(db.DBDT)
*db is a class file, dbda is the data adapter, and dbdt is the data table
but i realized these changed are only effected the data table and not the actual database. How can I get it to where it will effect only the database rows that are inside of the data table filled using the query?
Update: I'm thinking my update function isn't written. I don't know if this should be a separate question or not, but how do I write the update function to only change fields in the database that has been changed on the data table??
Do not call
db.DBDT.AcceptChanges()
before
db.DBDA.Update(db.DBDT)
Doing so marks everything in the datatable as not changed. See here especially in remarks section.
Just call the update method and the acceptchanges should be called automatically for you.

Calling a subroutine as part of a SQL Transaction

My project is an orders application, where users can enter orders from different customers, using an UltraGrid to enter and edit data. When the Delete key is pressed on the keyboard, it prompts a MsgBox for the user to confirm they want to delete the selected row, and if so, it runs a DELETE query to delete that row from the database.
I also have a Save button to allow the user to save the order/changes made to the order. Ideally, I only want the row in the grid to delete temporarily as, if the user then doesn't save the order, the order line shouldn't be deleted permanently from the database.
If I put the DELETE query into a separate subroutine, can I then call this subroutine from my class that is saving it as part of the transaction?
This seems like it isn't going to work, as I'd not only need to call the query, but also somehow store the deleted row somewhere temporarily so that it knows which data to delete in the transaction, as well as a Boolean variable to tell it whether there is even any data to delete...
Are there any simpler ways of doing this? Would the above way even work?
Sorted it... Nothing actually complex required at all, just needed to change the code, as below:
Try
Dim Dc As New OleDbCommand
Dim rowcode As String = ""
rowcode = dr.Item("Product_Code").Value
Changed to:
Try
Dim Dc As New OleDbCommand
Dim rowcode As String = ""
rowcode = dr.Item("Product_Code", DataRowVersion.Original)
Simplest way of doing it, is keeping all of your changes in-memory (additions, modifications and deletions) and then synchronizing them to the database when you hit your Save button.
Possibly, you'll need an AJAX action to add the operation to the server-side and a client-side script to update the row on the grid.
Grid does not work with back-end database. It is only dealing with its local DataSource. So when you save the data back to your database check for deleted rows and preserve them.
If you want to update the local data source only on save button click you can set the grid's UpdateMode to OnUpdate. Then you will need to call grid's UpdateData method. Again, this will update your local data source. How and when the local data source will update the back-end database has nothing in common with the grid. So depending on the type of your local data source you will need to handle checking for deleted rows before you send updated data back to database.

VB.NET Update Access Database with DataTable

I've been perusing some hep forums and some help books but cant seem to get my head wrapped around this. My task is to read data from two text files and then load that data into an existing MS Access 2007 database. So here is what i'm trying to do:
Read data from first text file and for every line of data add data to a DataTable using CarID as my unique field.
Read data from second text file and look for existing CarID in DataTable if exists update that row. If it doesnt exist add a new row.
once im done push the contents of the DataTable to the database.
What i have so far:
Dim sSQL As String = "SELECT * FROM tblCars"
Dim da As New OleDb.OleDbDataAdapter(sSQL, conn)
Dim ds As New DataSet
da.Fill(ds, "CarData")
Dim cb As New OleDb.OleDbCommandBuilder(da)
'loop read a line of text and parse it out. gets dd, dc, and carId
'create a new empty row
Dim dsNewRow As DataRow = ds.Tables("CarData").NewRow()
'update the new row with fresh data
dsNewRow.Item("DriveDate") = dd
dsNewRow.Item("DCode") = dc
dsNewRow.Item("CarNum") = carID
'about 15 more fields
'add the filled row to the DataSet table
ds.Tables("CarData").Rows.Add(dsNewRow)
'end loop
'update the database with the new rows
da.Update(ds, "CarData")
Questions:
In constructing my table i use "SELECT * FROM tblCars" but what if that table has millions of records already. Is that not a waste of resources? Should i be trying something different if i want to update with new records?
Once Im done with the first text file i then go to my next text file. Whats the best approach here: To First look for an existing record based on CarNum or to create a second table and then merge the two at the end?
Finally when the DataTable is done being populated and im pushing it to the database i want to make sure that if records already exist with three primary fields (DriveDate, DCode, and CarNum) that they get updated with new fields and if it doesn't exist then those records get appended. Is that possible with my process?
tia
AGP
Loading every text file into memory is the better performing option, and easier to code. This is of course fully dependent on how much memory you have available, and how big your text files are.
My approach would be to first load all of the data from the files into a DataTable. Then convert this table into XML. You can then pass the XML into a Stored Procedure. This stored procedure will convert the XML into either a Table Variable or Temporary table that you can run SQL queries off of.
From here it’s a simple case of doing a “Not Exists” query in your SP on tblCars with the data you’ve passed in, and inserting were applicable.
In my mind this is by far the best performing option, there’s no need for your application to pull any data out of SQL. SQL is optiomized for these kinds of things and will out perform a application hugely.
If you wanted to get really clever about it you could read each text file using a worker thread, and load them into SQL as soon as they’ve been read. It would save on memory usage and be very fast.