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
Related
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
In R, I have a SQL Server connection with this database:
From this answer I understand that these levels are catalogs (=databases), schemas, and tables. The following code:
library(odbc)
library(DBI)
library(RSQlite)
library(dbi)
confull <- odbc::dbConnect(odbc(),
Driver = "SQL Server",
Server = "XXX")
odbcListObjects(confull, schema="schema")
Yields:
name type
1 DBAInfo catalog
2 InBluePrism catalog
3 master catalog
4 msdb catalog
5 tempdb catalog
Questions:
How can I extract the full structure tree of this database, not just the catalogs?
How can I progammatically save (clone) this whole database (including all tables, schemas, and catalogs) into a local SQLite table?
For the first question I have tried the following:
> all_schemas <- DBI::dbGetQuery(confull, "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA")
> all_schemas
SCHEMA_NAME
1 dbo
2 guest
3 INFORMATION_SCHEMA
4 sys
5 CCAutomation
6 XXXXXX\\xxxAdmin
7 XXXXXX\\z_swmon
8 NT AUTHORITY\\SYSTEM
9 XXXXXX\\z_Backup
10 db_owner
11 db_accessadmin
12 db_securityadmin
13 db_ddladmin
14 db_backupoperator
15 db_datareader
16 db_datawriter
17 db_denydatareader
18 db_denydatawriter
For the second question, I have tried:
to generate scripts in SQL Server, but I get an error and moreover I would like to keep this programmatic.
to just save all the tables given by dbListTables(confull) however, I then lose the information about the catalogs and schemas these tables belong to.
EDIT: the following link also contains useful information
I don't know which version of the SQL Server you have. I'm basing it on what I have which is SQL Server 2008 and 2016.
To have CLI tool you can download Export2SqlCE.zip
Description:
SQL Server 2005/2008 command line utility to generate a SQL Compact or SQLite compatible script with schema and data (or schema only)
After downloading you can run it to extract the information using:
Export2SQLCE.exe "Data Source=(local);Initial Catalog=<your_database>;Integrated Security=True" your_database.sql sqlite
We can use Powerbuilder pipeline of version 9/10/10.5 depends on your SQL Server version. Database and data will be easily migrated all you must know is to create ODBC/Database connections which is the matter of few clicks.
Use a Pipeline object by defining a standard class user object inherited from the built-in Pipeline object in the User Object painter. We can then access the Pipeline events by writing scripts that contain code for the events.
This is how we can execute pipeline by writing the script.
The scenario of this case is we want to pipeline a table from one database to another database. So, first, we need at least 2 transaction objects, which mean we must declare first in the top of the script. Since we have a default database connection SQLCA, we only have declare another new transaction object called SQLCAtarget, which represent for the target database connection. Remember, in this case, SQLCA will be the source of database connection
transaction SQLCAtarget // declare this variable as INSTANT variable
SQLCA.DBMS = 'your source dbms name'
SQLCA.Database = 'your source database name'
SQLCA.LogId = 'your source database login id'
SQLCA.LogPass = 'your source database password'
SQLCA.ServerName = 'your source database server'
CONNECT USING SQLCA;
SQLCAtarget = CREATE transaction
SQLCAtarget.DBMS = 'your target dbms name'
SQLCAtarget.Database = 'your target database login id'
SQLCAtarget.LogPass = 'your target database password'
SQLCAtarget.ServerName = 'your target database server'
SQLCAtarget.LogId = 'your target database login id'
CONNECT USING SQLCAtarget;
Next step, we need to build a pipeline object by clicking the Pipeline painter in the main toolbar. Remember, use MAIN TOOLBAR, if we want to pipeline the data to ANOTHER DATABASE.
Setup the source database and the target database profile, choose the table(s), column(s) and criteria(s), then save as pl_mypipeline.
to begin with, Click on pipeline button from powerbuilder
Choose the source and target of Pipeline
set the table, column and criteria of your pipeline
save your pipeline
Create a window, then put one datawindow object and one button object. We don't need to put dataobject for the datawindow, just keep it blank. And put the script below at clicked event in button object.
integer iReturn
pipeline myPipeline
myPipeline = CREATE pipeline
myPipeline.DataObject = "pl_mypipeline"
iReturn = myPipeline.Start(SQLCA, SQLCAtarget, dw_1)
// always disconnect your database connection
DISCONNECT USING SQLCA;
DISCONNECT USING SQLCAtarget;
iReturn should have 0 (zero) value if the pipeline runs smoothly.
I'm trying to create an Update Query in Access 2010 to update a duplicate table on our shared drive from the user's local copy.
The Access program itself uses the usual split front end / back end.
Due to frequent drops over VPN, we came up with a method for:
downloading the latest version of the front end and a copy of the back end to the user's local drive
then running off of the local front end / back end (with the two linked)
and then using VBA to update individual records on both the local and network locations, unless the network drive is unavailable, where it then dumps the updated data into an array to be attempted again at program close.
I have two identical tables (one on the local and one on the network) that I need to create an Update Query to update any changes made in the local table to the one on the network so that it can be stored on the network database for the next user on their machine.
UPDATE HiringMgrData As NetworkHiringMgrData IN '\\ServerName\FilePath\HREmails_be.accdb'
SET NetworkHiringMgrData.UserName = HiringMgrData.UserName,
NetworkHiringMgrData.UserPhone = HiringMgrData.UserPhone,
NetworkHiringMgrData.UserEmail = HiringMgrData.UserEmail
WHERE NetworkHiringMgrData.ID IN (SELECT ID FROM HiringMgrData)
This gives me an error when it gets to the SET statements, and clicking through simply blanks the fields in the network table.
I'm trying to "trick" Access into treating the table in the network database as NetworkHiringMgrData, while keeping the name of table in the the local database HiringMgrData, in hopes that Access will be able to distinguish between the two.
In reality, both the local and network databases have a table named HiringMgrData with field names of ID, UserName, UserPhone, and UserEmail.
I was able to get the Append Query to work using:
INSERT INTO HiringMgrData IN '\\ServerName\FilePath\HREmails_be.accdb'
SELECT HiringMgrData.*
FROM HiringMgrData;
which simply adds any new records from the HiringMgrData table in the local database to the HiringMgrData table in the network database, but I cannot update the existing records.
Try the below. I was attempting to do something similar on my MS Access Database and for some reason this worked for me instead of using IN 'network path'
UPDATE [\\ServerName\FilePath\HREmails_be.accdb].HiringMgrData As NetworkHiringMgrData
inner join HiringMgrData as LocalHiringMgrData on NetworkHiringMgrData.ID = LocalHiringMgrData.ID
SET NetworkHiringMgrData.UserName = LocalHiringMgrData.UserName,
NetworkHiringMgrData.UserPhone = LocalHiringMgrData.UserPhone,
NetworkHiringMgrData.UserEmail = LocalHiringMgrData.UserEmail;
I think your WHERE clause is wrong and should be
WHERE NetworkHiringMgrData.ID = HiringMgrData.ID;
Note that this may generate lots of network traffic as all records are updated. Maybe your application can manage an isChanged flag and update only those records.
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.
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.