MS Access Auto De-link and Re-link an Excel file? - ms-access

I have a link-table from an Excel file, but sometimes it "breaks" for reasons unknown to me (other people manipulate this file externally and for whatever reason, the link in the database corrupts even though the filename is the same, etc).
The only way I can fix this issue is by delinking the file and then re-linking it. Is there a way to do this automatically when someone opens the database? (I know about autoexec macros and VBA and everything, but I was unable to find VBA code to delete the old link and re-link the file again).

if the file path does not change you can simply relink the source. You can do it to connect all the linked tables to be connected or you can specifically tell one linked table to be reconnected.
pseudo would be:
Go through your table collection
check if the table is a linked table / or any condition
use the .Connect property to set/renew the connectionstring/path for linked tables.
use the .RefreshLink method to reconnect the table
in code it would be something like this:
For Each tdf In db.TableDefs
If tdf.connect <> vbNullString Then
'you can renew the connectionstring if you want by
'tdf.connect = Your_connectionString & ";TABLE=" & tdf.name
'and to reconnect
tdf.RefreshLink
End If
Next tdf

Related

How can I refresh a linked table in VBA when it contains a multi-valued field?

I have some VBA that programmatically updates the location of linked tables so that the front end of my database can be easily pointed at a different back end, without needing to click around in the Linked Table Manager. The technique is explained in this Microsoft blog post. This should be as simple as running the following code for each linked table in CurrentDb.TableDefs:
tableDef.Connect = ";DATABASE=" & newBackEndPath
tableDef.RefreshLink
However, when the table contains a multi-valued field, Access provides the following unhelpful and misleading error message:
Run-time error '3125':
'[table name]' is not a valid name. Make sure that it does not include invalid characters or punctuation and that it is not too long.
The same error appears when manually updating the links from the Linked Table Manager, although sometimes after a few attempts, the update will work without an error message. To work around the problem, I'm trying to refresh the link by creating a new TableDef and then renaming it over the old one:
Dim tdf As TableDef
Set tdf = CurrentDb.CreateTableDef(originalTableName & "_Copy")
tdf.Connect = ";DATABASE=" & newBackEndPath
tdf.SourceTableName = tableName
With CurrentDb.TableDefs
.Append tdf
.Refresh ' Required?
End With
RefreshDatabaseWindow ' Required?
DoEvents ' Required?
DoCmd.Rename originalTableNameName, acTable, originalTableNameName & "_Copy"
This usually works, but sometimes DoCmd.Rename throws the following run-time error:
Run-time error '7874':
Microsoft Access can't find the object '[table name]_Copy'.
If I enter the debugger, this usually triggers some kind of refresh and the _Copy table appears in the navigation pane. If I press F5 at this point, DoCmd.Rename executes with no problems. Clearly, there is some delay after the TableDef is appended before it can actually be found and renamed. I've added the TableDefs.Refresh, RefreshDatabaseWindow and DoEvents lines in an attempt to force the new table to appear, but they don't seem to help. Even forcing a delay of a few seconds doesn't seem to work, but somehow, opening the debugger does.
Is there any reliable way to refresh a linked table that contains a multi-valued field?
(I ignored the advice to avoid using multi-valued fields when I started this project, because I wanted users to be able to filter on multi-valued fields using the Quick Filters on a split form datasheet. This function is very helpful, but I'm beginning to wish I just built my own filtering UI after encountering this and numerous other bugs in the implementation of multi-valued fields.)
You could try a different approach altogether, by using DoCmd.TransferDatabase:
DoCmd.TransferDatabase acLink, "Microsoft Access", newBackEndPath, acTable, tableName, tableName
DoCmd.TransferDatabase is similar to using the GUI to link the table. It handles steps like refreshing the database pane for you. I usually recommend using TableDefs instead, but this situation might be an exception.
Of course, I support Sergey's advice to not use a multi-valued field. I'm a fan of the user experience of multi-valued fields and the associated comboboxes, but it has far-going consequences to use a MVF, like not being able to migrate your database to SQL server in the future

In access 2007, when you split the database into two files, can you tell it to look in the frontend directory for the backend file?

I'm playing around with splitting access databases. It appears that each table contains a hard link to the backend file in the linked table manager.
But if I wanted to send the file pair to someone through email to look at, the hard links will break. Right now we're at separate offices just testing changes to the program. This isn't in production. I don't want them to get into the development mode and edit the linked table manager because it would be too hard.
Is there a way to tell access to simply look in the front end file's directory for the backend file? Is there a way to force a prompt on the front end to let them choose the location of the backend file?
Thanks!
The simple solution is to on startup check if the table link(s) point to the current directory, and if not, then you run re-link code. That way the pair of files will work if you move the pair to a different folder or re-name the folder.
The above is a common setup and EVEN recommend for single user applications that SHOULD be split and benefit by being split.
So on startup, check the path of a linked table. I use the following code to return the path of currently linked tables.
Function strBackEndPath() As String
' returns the path name to the back end
' and includes tralinig \
Dim mytables As TableDef
Dim strTempBack As String
Dim strFullPath As String
strFullPath = ""
For Each mytables In CurrentDb.TableDefs
If Left(mytables.Connect, 10) = ";DATABASE=" Then
strFullPath = Mid(mytables.Connect, 11)
Exit For
End If
Next mytables
strBackEndPath = Left(strFullPath, InStrRev(strFullPath, "\"))
End Function
With above, then on startup I can go:
If CurrentProject.path & "\" <> strBackEndPath Then
' call re-link code
End If
And there are TONS of re-link code examples floating around but here is a link to some re-linking code.
http://access.mvps.org/access/tables/tbl0009.htm
Thus if the links don’t point to the back end database in the same folder, then re-linking will ONLY occur once and after that only the above “test” to ensure that front end and back end are are linked.
If the folder is renamed or as noted a user moves the files to a different location then again the re-link will occur.
Right-click on the front-end tables and select Linked Table Manager. From there, you can browse for the location of the back-end tables

Reattaching [Event Procedure] in Access

Due to requirements to not share data between clients, I have an MS Access 2010 data base that I use to extract data from our SQL Server into a small .accdb which we then send to a client, they modify, then I load the data back to the Server.
In my 'Master' Access database (EDIT2: I use Access as a front end to SQL Server), I have a button that will create a client specific .accdb (EDIT2: This has a local table that contains the client's specific data for them to moidify). This code simply copies a template .accdb with forms, code, etc & names it appropriately for the client.
Unfortunately when this copy is made, all the event procedure connections are lost from the properties box. The code still exists in the module, though. This is a fairly well-known issue and is well documented on Google. The general solution is to go through each form & reset the properties for every form & control that needs an event, then Access will reconnect it with the existing code. That's ok, once. I'll have this copy/loss issue dozens or hundreds of times.
I found one reference from ~2003 March, 2004 to dynamically identify missing code (EDIT2: [Event Procedure] references in the properties box) & set the property to [Event Procedure] to fix this. However, when trying to identify if an object should have an event handler, the code relies on this statement
DLookup("EventProcedureSuffix", "EventProcedures", "EventName = '" & prpCurr.Name & "'")
and that generates an error 3078 saying it cannot find a table or query named 'EventProcedures' (EDIT2: which seems to have been a system table in the older version of Access that the code was based on). Does anyone know what happened to the 'EventProcedures' table in Access 2010? Has it been renamed, is it no longer accessible, is there a replacement?
This also begs the question of how do I fire this code in the first place. I have it on the OnOpen event of the main form that is opened when the DB is opened, but if the event handler is disconnected, that won't fire, either...
EDIT: Found the link to the source of the code I'm using: http://www.accessmvp.com/djsteele/Access/AA200403.zip
Instead of trying to re-attach the Event Procedures after the fact you might try to find a method that creates a new user database in a way that preserves the Event Procedure links.
The following Access 2010 code seems to work fine for me. It creates an Access 2003 format .mdb file and then exports a Table and a Form. The form has a button with code behind it, and the button works fine when I open the form within the .mdb file.
Option Compare Database
Option Explicit
Public Function CreateUserDatabase()
Dim fd As Object ' Office.FileDialog
Dim db As DAO.Database
Dim newDbPath As String
Set fd = Application.FileDialog(2) ' msoFileDialogSaveAs
fd.Title = "Save User Database As..."
fd.InitialFileName = "UserDB.mdb"
fd.Show
If fd.SelectedItems.Count <> 0 Then
newDbPath = fd.SelectedItems(1)
If UCase(Right(newDbPath, 4)) <> ".MDB" Then
newDbPath = newDbPath & ".mdb"
End If
On Error Resume Next
Kill newDbPath
On Error GoTo 0
Set db = DBEngine(0).CreateDatabase(newDbPath, dbLangGeneral, dbVersion40)
db.Close
Set db = Nothing
DoCmd.TransferDatabase acExport, "Microsoft Access", newDbPath, acTable, "UserData", "UserData", False
DoCmd.TransferDatabase acExport, "Microsoft Access", newDbPath, acForm, "UserForm", "UserForm", False
MsgBox "The user database has been created.", vbInformation
End If
Set fd = Nothing
End Function

Access 2007 VBA: Set Tabledef.Connect property to invalid path

I've been asked to do some maintenance on an Access 2007 VBA database.
It has linked tables to another Access database in the same folder. It had hard-coded links to that database, so if the user copied the folder to a new folder, it tried to use the linked database in the original folder. They asked me to eliminate the danger of using the wrong linked database in that scenario.
I added code that runs when the database is opened, to make it reset the links to the database in it's own folder. If the linked database isn't there or was renamed, the user is prompted to browse to the correct database. So far so good.
But if the user cancels that dialog, I don't want to leave it connected to the wrong database. I want to set the linked tabledef's Connect property to the "correct" path even though the table is not there. Then the user will get an error that the linked table isn't there until they copy in the linked database -- rather than inadvertently use the wrong database.
When I use Resume Next to get past the error that is raised when I set the Connect property to a nonexistent database, the change doesn't stick, leaving it connected to the wrong database. So for now, I'm closing the database when that happens (after alerting the user that the linked database can't be found). That's safe in terms of not using the wrong database, but I don't think it's the ideal user experience.
So -- is it possible to set the Tabledef's Connect property to a nonexistent database?
Thanks,
Greg
is it possible to set the Tabledef's Connect property to a nonexistent database?
I don't think so. I recommend you delete all of the linked tables first, and then if there's no database to connect to, show an error saying so.
In order to relink the tables you will then need to have a local table in your frontend file that holds a list of all tables to be linked. Then you'll need to loop through that list every time you need to relink the tables, assuming that the links have all been deleted.
In order to update table links to render them invalid you need to
create a temporary copy of the back-end database (or perhaps a temporary copy of a "skeleton" back-end database with empty tables),
update the table links to point to the temporary database, and then
delete the temporary database.
For example, if I run the following code
Option Compare Database
Option Explicit
Sub MakeBadLink()
Const linkedTableName = "myLinkedTable" ' test value
Dim cdb As DAO.Database, tbd As DAO.TableDef
Dim tempFolder As String, linkedDb As String, tempDb As String
Dim fso As FileSystemObject
Set cdb = CurrentDb
linkedDb = Mid(cdb.TableDefs(linkedTableName).Connect, 11) ' remove ";DATABASE=" prefix
Set fso = New FileSystemObject
tempFolder = fso.GetSpecialFolder(TemporaryFolder) & "\"
tempDb = tempFolder & fso.GetFileName(linkedDb)
fso.CopyFile linkedDb, tempDb, True
Set tbd = cdb.TableDefs(linkedTableName)
tbd.Connect = ";DATABASE=" & tempDb
tbd.RefreshLink
Set tbd = Nothing
Set cdb = Nothing
fso.DeleteFile tempDb
Set fso = Nothing
End Sub
then any subsequent attempts to use [myLinkedTable] result in the error
Could not find file `C:\Users\Gord\AppData\Local\Temp\myDb.accdb'.

MS Access Can't Link to Encrypted Backend Database

I've got a quandry. I've developed an Access app and I'm getting ready to distribute it. I've just split the database. (I know, some say I should've developed it split from the start... I didn't) I've also just encrypted the backend database. In the frontend, I've linked to the backend and entered the correct password when prompted. The linked tables are now appearing in my fronend database. However, when I try to access one of the linked tables, I get a pop-up message that simply says "Not a valid password".
I've tried deleting the linked tables and relinking. I've tried updating the link. Nothing seems to work. Every search I've done assumes the links were created BEFORE the encryption happened and no password was entered. This is not the case here.
Can anyone please help?
Windows 7 - Access 2010
Multiguy
From comments
OOOOOPPPPPSSSS!!!! Ok, I found the problem. Access doesn't like the
use of other characters. I had a set of parenthesis in my password.
Removed that and all is well! :-)
– MultiGuy
I'd like to add to this; a password for a back end table connection can be updated in a VBA macro. Add the following lines and replace the name for the linked table & the password.
Dim cdb As DAO.Database
Set cdb = CurrentDb
cdb.TableDefs("Projects").Connect = "MS Access;PWD=PaSsWoRd;DATABASE=C:\Users\bob.smith\Desktop\Split\Database_NEW_be.accdb"
cdb.TableDefs("Projects").RefreshLink
I found this was useful after splitting a database into a front end and back end using the built in split functionality. I needed to encrypt the back end for security purposes and didn't want to have to recreate all the data connections - isn't that the point of using the split function?
Duplicate the above lines for each linked table and let the macro run through. The linked tables should resume working after this.
This answer solved an issue for me. So I am upvoting, and also I want to provide an enhanced version that you can run on all tables:
Public Sub RevisePasswordForLink()
Dim cdb As DAO.Database
Set cdb = CurrentDb
Dim tdf As TableDef, colTdf As TableDefs, strConnect As String
Set colTdf = cdb.TableDefs
strConnect = "MS Access;PWD=paSsWoRd;" _
"DATABASE=C:\Users\bob.smith\Desktop\Split\Database_NEW_be.accdb"
For Each tdf In cdb.TableDefs
''I believe best to skip the hidden tables ("MSys*")
If Not tdf.Name Like "MSys*" Then
''If your DB has any local tables, you can save yourself some errors
''by filtering them out (similar to hidden tables).
cdb.TableDefs(tdf.Name).Connect = strConnect
cdb.TableDefs(tdf.Name).RefreshLink
Debug.Print " " & tdf.Name
End If
Next tdf
Set cdb = Nothing
Debug.Print "FINISHED "
End Sub
I came across this thread when I was having a similar problem with Access 2013. I'd encrypted the backend successfully. Each time I opened the backend, I could successfully open the backend using the password I'd used to encrypt the backend.
So, I opened the frontend, deleted the previously linked tables, and re-linked to the newly encrypted backend. As expected, during the link process, it asked me for the password to the backend. I entered the correct password (I know it was correct, because I pasted it instead of typing it) and everything seemed to work correctly. The tables all showed up in the objects list in the frontend. However, if I tried to open a linked table, I would get a message box stating "Not a valid password."
After visiting some other threads, I tried using a password on the backend that did not have any special characters and did not have any spaces. Then relinking those in the frontend. Presto! That solved the problem.
So, try the following if you are getting the "Not a valid password" in the frontend even if you can open the backend just fine if you manually load it yourself: Eliminate any spaces or punctuation from the backend password and then delete and re-link the linked tables in the frontend.