creating a document database - ms-access

I camse across an old post which had the pefect solution for my requirement - 'Creating a Document Database Using Microsoft Access' with the answer provided by Renaud BomPuis in the form of a sample database (https://dl.dropboxusercontent.com/u/52900980/StackOverflow/SO25044339.accdb).
I have been able to manipulate the source code for this to suit my needs and successfully insert it into my main database. The only problem I have is that it creates a new record at the wrong point for me. When the user clicks 'Upload File' a new record is created and a form opens to be able to select the file using file dialog. But if the user changes their mind and clicks cancel, the record is already created but empty of a file path.
I would like to be able to only create a new record if the user confirms it but I cannot seem to manipulate the code into the correct order for it to work.
Can anybody help please? Many thanks.
EDIT: Code from comment
Private Sub btnUploadDoc_Click() ' Create a new record in the Documents table for the selected Works No
Dim DocID As Variant
Dim db As dao.Database
Dim rs As dao.Recordset
Set db = CurrentDb()
Set rs = db.OpenRecordset("tblDocuments", dbOpenDynaset, dbFailOnError)
With rs
.AddNew !WorksNo = cboWorksNo
.Update
.Move 0, .LastModified
DocID = !DocID
.Close
End With
Set rs = Nothing
Set db = Nothing
DoCmd.OpenForm "frmDocSelect", WhereCondition:="DocID=" & DocID
End Sub

This will not be a trivial change, since (I assume) frmDocSelect depends on an existing record in tblDocuments.
The best way to proceed is probably to simply delete the new record if the user clicks Cancel.
Something like
Sub cmdCancel_Click()
Dim DocID As Long
DocID = Me.DocID
' Close form before deleting, to avoid a flicker of "#Deleted"
DoCmd.Close acForm, Me.Name, acSaveNo
CurrentDb.Execute "DELETE * FROM tblDocuments WHERE DocID=" & DocID
End Sub

Related

Save record changes - Access ado form

Help please!
I've created a database for logging service calls, based on one of Microsoft's templates (Very loosely based now!)
I have a "Case Details" form, which is opened from a case list split form. Originally, this was opening the form with a filter - which I assume means that it is actually loading the whole recordset?
As I assume (hopefully correctly) that this will be quite inefficient as the database grows, I decided to change the form to open and ADO recordset, using a SQL statement, only selecting the record I want.
The code for this is as follows, and the form opens with the correct record, and I can update the fields.
Private Sub Form_Load()
On Error GoTo Form_Load_Err
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
If (IsNull(TempVars!currentid)) Then
Me.DataEntry = True
Else
'Use the ADO connection that Access uses
Set cn = CurrentProject.Connection
'Create an instance of the ADO Recordset class,
'and set its properties
Set rs = New ADODB.Recordset
With rs
Set .ActiveConnection = cn
.Source = "SELECT * FROM Cases WHERE ID = " & TempVars!currentid & ";"
.LockType = adLockOptimistic
.CursorLocation = adUseClient
.CursorType = adOpenStatic
.Open
End With
'Set the form's Recordset property to the ADO recordset
Set Me.Recordset = rs
Set rs = Nothing
Set cn = Nothing
End If
Call IntializeCollections
Select Case (Me.Status)
Case 7, 8
Call EnableControls(mcolgrpAllFields, False)
End Select
Form_Load_Exit:
Exit Sub
Form_Load_Err:
MsgBox Error$
Resume Form_Load_Exit
End Sub
However, here is the problem. What the blinking heck do I do to save my changes? I've done some googling, and looked at MS Access Form Bound to ADO Disconnected Recordset but I'm still absolutely stumped.
Is there as simple "save the updates" command? or do I have to iterate through each field, check for changes, then save those changes?
Can someone please point me in the right direction?
Thanks in advance
If you need to update one record at a time try this solution for disconnected recordsets: http://www.techrepublic.com/blog/how-do-i/how-do-i-pass-data-over-a-network-using-disconnected-recordsets/

How to see who is using my Access database over the network?

I actually have 2 questions:
1. How might I see who is using my Access database?
E.g: There is someone with an Access database opened and it created the .ldb file, I would like to see a list of who opened that database (it could be more than one person).
2. How might I see who is using a linked table?
E.g: I have 10 different Access databases, and all of them are using a same linked table. I would like to see who is using that linked table.
I don't even know if it's really possible, but I really appreciate your help!
For you information: The main problem is that lots of people use the same Access in the same network drive, so when I need to change it I have to kick them all out, but I never know who is actually using it.
Update: Rather than reading and parsing the .ldb/.lacdb file, a better approach would be to use the "User Roster" feature of the Access OLEDB provider as described in the Knowledge Base article
https://support.microsoft.com/en-us/kb/285822
and in the other SO question
Get contents of laccdb file through VBA
Original answer:
I put together the following a while ago. It looked promising but then I discovered that computers are not immediately removed from the lock file when they disconnect. Instead, Jet/ACE seems to (internally) mark them as inactive: If ComputerA disconnects and then ComputerB connects, ComputerB overwrites ComputerA's entry in the lock file.
Still, it does provide a list of sorts. I'm posting it here in case somebody can offer some suggestions for refinement.
I created two tables in my back-end database:
Table: [CurrentConnections]
computerName Text(255), Primary Key
Table: [ConnectionLog]
computerName Text(255), Primary Key
userName Text(255)
A VBA Module in my back-end database contained the following code to read (a copy of) the lock file and update the [CurrentConnections] table:
Public Sub GetCurrentlyConnectedMachines()
Dim cdb As DAO.Database, rst As DAO.Recordset
Dim fso As Object '' FileSystemObject
Dim lck As Object '' ADODB.Stream
Dim lockFileSpec As String, lockFileExt As String, tempFileSpec As String
Dim buffer() As Byte
Set cdb = CurrentDb
cdb.Execute "DELETE FROM CurrentConnections", dbFailOnError
Set rst = cdb.OpenRecordset("SELECT computerName FROM CurrentConnections", dbOpenDynaset)
lockFileSpec = Application.CurrentDb.Name
If Right(lockFileSpec, 6) = ".accdb" Then
lockFileExt = ".laccdb"
Else
lockFileExt = ".ldb"
End If
lockFileSpec = Left(lockFileSpec, InStrRev(lockFileSpec, ".", -1, vbBinaryCompare) - 1) & lockFileExt
'' ADODB.Stream cannot open the lock file in-place, so copy it to %TEMP%
Set fso = CreateObject("Scripting.FileSystemObject") '' New FileSystemObject
tempFileSpec = fso.GetSpecialFolder(2) & "\" & fso.GetTempName
fso.CopyFile lockFileSpec, tempFileSpec, True
Set lck = CreateObject("ADODB.Stream") '' New ADODB.Stream
lck.Type = 1 '' adTypeBinary
lck.Open
lck.LoadFromFile tempFileSpec
Do While Not lck.EOS
buffer = lck.Read(32)
rst.AddNew
rst!computerName = DecodeSZ(buffer)
rst.Update
buffer = lck.Read(32) '' skip accessUserId, (almost) always "Admin"
Loop
lck.Close
Set lck = Nothing
rst.Close
Set rst = Nothing
Set cdb = Nothing
fso.DeleteFile tempFileSpec
Set fso = Nothing
End Sub
Private Function DecodeSZ(buf() As Byte) As String
Dim b As Variant, rt As String
rt = ""
For Each b In buf
If b = 0 Then
Exit For '' null terminates the string
End If
rt = rt & Chr(b)
Next
DecodeSZ = rt
End Function
The following code in the Main_Menu form of the front-end database updated the [ConnectionLog] table
Private Sub Form_Load()
Dim cdb As DAO.Database, rst As DAO.Recordset
Dim wshNet As Object '' WshNetwork
Set wshNet = CreateObject("Wscript.Network")
Set cdb = CurrentDb
Set rst = cdb.OpenRecordset("SELECT * FROM ConnectionLog", dbOpenDynaset)
rst.FindFirst "ComputerName=""" & wshNet.computerName & """"
If rst.NoMatch Then
rst.AddNew
rst!computerName = wshNet.computerName
Else
rst.Edit
End If
rst!userName = wshNet.userName
rst.Update
Set wshNet = Nothing
End Sub
Finally, the following form in the back-end database listed [its best guess at] the current connections
It is a "continuous forms" form whose Record Source is
SELECT CurrentConnections.computerName, ConnectionLog.userName
FROM CurrentConnections LEFT JOIN ConnectionLog
ON CurrentConnections.computerName = ConnectionLog.computerName
ORDER BY ConnectionLog.userName;
and the code-behind is simply
Private Sub Form_Load()
UpdateFormData
End Sub
Private Sub cmdRefresh_Click()
UpdateFormData
End Sub
Private Sub UpdateFormData()
GetCurrentlyConnectedMachines
Me.Requery
End Sub
Easy. Open the .ldb file in notepad (or any text editor) and you can see the machine names.
RE: How might I see who is using my Access database?
•E.g: There is someone with an Access database opened and it created the .ldb file, I would like to see a list of who opened that database (it could be more than one person).
Just happened across this while looking for something else, and I thought I might share what I do for this. Note that this assumes that the host computer (the computer on which the database file resides) uses file sharing to provide access to the file.
You will need to be on the host computer, or have authority to connect to that machine.
click Start
right-click My Computer and select Manage
if you're not on the host computer, right-click 'Computer Management' and enter the host's name
Expand 'Shared Folders' and click on 'Open Files'
At the right is the list of currently open files with the username for each current user
I agree with Gord's Original answer. I used this code on my database, it seems that there is a way around computers not being taken out of CurrentConnections upon exit of the DB.
I placed this on my main menu form because it is always open until the user exits. I used the unload event on my form to get this to work, and it works awesome! Here is my code
p.s. Ignore SetWarnings I just have that on so the user doesn't have to click through prompts.
Private Sub Form_Unload(Cancel As Integer)
Dim wshNet As Object
Dim deleteSQL As String
Set wshNet = CreateObject("WScript.Network")
DoCmd.SetWarnings False
deleteSQL = "DELETE tblCurrentConnections.* " & _
"FROM tblCurrentConnections WHERE[computerName] = '" & wshNet.computerName & "';"
DoCmd.RunSQL deleteSQL
DoCmd.SetWarnings True
End Sub

Microsoft Access Sub Form Write Conflict Troubles

I have a form which contains a subform which displays editable fields linked to one my tables. For a project I'm currently working on, one of the requirements is that I have to track when the last change was made to a record and who did so.
So what I've done is for each editable textbox or combobox within the form and subform I've made it so they have events on their BeforeUpdate and AfterUpdate events.
For example my BeforeUpdate for a textbox:
Private Sub textbox_BeforeUpdate(Cancel As Integer)
If Not isValidUser Then
Cancel = True
Me.textbox.Undo
End If
End Sub
and my AfterUpdate is:
Private Sub textbox_AfterUpdate()
updateRecord Me.textbox.Value, UserNameWindows
End Sub
and updateRecord is:
Public Sub updateRecord(bucNumber As String, updater As String)
Dim Dbs As Object
Dim rst As Object
Dim fldEnumerator As Object
Dim fldColumns As Object
sqlStatement = "SELECT fName " & _
"FROM t_Staff " & _
"WHERE uName='" & updater & "';"
'Getting fullname of user via username
Set rst = CurrentDb.OpenRecordset(sqlStatement)
'Setting fullname to updater variable
updater = rst(0)
'Clean Up
Set rst = Nothing
'Opening Bucket Contents
Set Dbs = CurrentDb
Set rst = Dbs.OpenRecordset("Bucket Contents")
Set fldColumns = rst.Fields
'Scan the records from beginning to each
While Not rst.EOF
'Check the current column
For Each fldEnumerator In rst.Fields
'If the column is named Bucket No
If fldEnumerator.Name = "Bucket No" Then
'If the Bucket No of the current record is the same as bucketNumber
If fldEnumerator.Value = bucNumber Then
'Then change the updated fields by updater and todays date
rst.Edit
rst("Last Updated By").Value = updater
rst("Last Updated On").Value = Date
rst.Update
End If
End If
Next
'Move to the next record and continue the same approach
rst.MoveNext
Wend
'Clean Up
Set rst = Nothing
Set Dbs = Nothing
End Sub
Okay now is the weird thing, this works totally fine when I make a modification to a control within the Main form, however as soon as a try to alter something in the subform it throws up a write conflict.
If I opt to save record it ignores my code for updating who last modified it and when and if I opt to discard the change it runs my code and updates it that it has been changed!
Anyone know what is wrong or of a better way to do this?

VBA and Access Form Filter

I have this form in access, the purpose of it is to work as a front end of a table which can be edited through this form. Initially when it loads I display in the form data from a recordset with the following query:
SELECT * FROM DATA
I want to be able to filter the data on the recordset once the form is open. I tried the following VBA code to accomplish this:
Private Sub Filter_Click()
If (IsNull(Me.Find_Field) Or Me.Find_Field = "") Then
rs.Close
Set rs = db.OpenRecordset("Select * from DATA ORDER BY ID)
rs.MoveFirst
LoadData (True)
Exit Sub
End If
Set rs = db.OpenRecordset("Select * from DATA WHERE ID = " & Me.Find_Field)
rs.MoveFirst
LoadData (True) ' Function that loads the data into the form
Exit Sub
As you all can see, I reload the recordset with a new filtered query. Up to this point it works, the problems begin when I try to modify a record.
Originally, when the form loads the recordset data, I am able to edit the data and the edited data would show in the table (which is what I want). But after I apply my filter, my code gives me the Run-Time error '3027': Cannot Update. Databse or object is read-only.
I am pretty much using the same code over and over to reload data from the table and it never gave me a problem until I 'overwrote' the source of the recordset. Any idea how can I resolve this issue? Thanks
I would prefer to use a standard Access bound form because it's simpler than what you appear to be doing.
I can change the form's RecordSource from the click event of my cmdApplyFilter button.
Private Sub cmdApplyFilter_Click()
Dim strSql As String
If Len(Me.txtFind_Field & vbNullString) > 0 Then
strSql = "SELECT * FROM tblFoo WHERE id = " & _
Me.txtFind_Field & " ORDER BY id;"
Me.RecordSource = strSql
End If
End Sub
If you're concerned someone might save the form with the filtered RecordSource, you can make the form always open with the unfiltered version.
Private Sub Form_Open(Cancel As Integer)
Dim strSql As String
strSql = "SELECT * FROM tblFoo ORDER BY id;"
Me.RecordSource = strSql
End Sub

open file from path stored in access db when user clicks button on form

I'm new to Access VBA development and being asked to debug and add features to an Access 2007 application that two previous developers worked on.
A form displays records from a database and shows a button for each record. The button is supposed to open a file using the appropriate path. But when the user clicks the button, it always uses the filepath from the first record that the form displays, instead of the filepath from the correct record.
The code looks like it is trying to use a bookmark to open the correct file, but as stated above, that isn't working. Here is the relevant code from the button click event. When I try to Debug.Print form.Bookmark to the immediate window, it just displays a question mark.
Dim rs As Recordset
Set rs = form.RecordsetClone
rs.Bookmark = form.Bookmark
Edit: adding more code per #Remou's request. When button is clicked:
Private Sub OpenFile_Click()
Form_FilingProcess.Subform_cmdOpenFile_Click Me
End Sub
Which calls:
Public Sub Subform_cmdOpenFile_Click(frm As Form)
Set rs = frm.RecordsetClone
rs.Bookmark = frm.Bookmark
And then it goes on to open the file.
If the button is for each record, there is no need for any messing around with the recordset. You can use the name of the control to get the file:
TheFile=Me.MyControl
It seems that you have both a form and subform. I am guessing from your answers that the set-up is something like this:
|------------------------------|
| Main Form |
--------------------------------
Sub form
--------------------------------
Row Button
--------------------------------
Row Button
--------------------------------
If the name of the button is OpenFile, try:
Private Sub OpenFile_Click()
MsgBox Me.NameOfAContolHere & ""
'Form_FilingProcess.Subform_cmdOpenFile_Click Me
End Sub
This can then be used to ope a file like so:
Private Sub OpenFile_Click()
FollowHyperlink Me.NameOfControlWithPathToFile
'Form_FilingProcess.Subform_cmdOpenFile_Click Me
End Sub
Here is what your sub should look like:
Public Sub Subform_cmdOpenFile_Click(frm As Form)
Dim CurrentBookmark as String
Set rs = frm.RecordsetClone
CurrentBookmark = frm.Bookmark
rs.Bookmark = CurrentBookmark
End Sub
Set a string variable to the value of the form's bookmark. Then set the recordset's bookmark to the string variable value.
Dim rs As Recordset
dim CurrentBookmark as String
Set rs = Me.RecordsetClone
CurrentBookmark = Me.Bookmark
rs.Bookmark = CurrentBookmark
http://msdn.microsoft.com/en-us/library/aa223967(office.11).aspx