I want to get the next value of the field next to the current row.
I used ADODB movenext and moveprevious together, but there is an error that the current context does not permitted.
How to fix that?
This is the code
objresultset.MoveNext()
yMark = objresultset.Fields(k1).Value
If xMark = yMark Then
m += 1
End If
objresultset.MovePrevious()
I'm not sure. Perhaps you provide too little information.
I assume that ADO recordset features might also dependent upon the underlying database system and/or your database connection properties. So perhaps your specific database/recordset instance does not support MovePrevious in your case.
But if it has worked before, or if it works in a small test application, perhaps you are trying to move beyond the last record in your recordset. In that case you might check the BOF/EOF property values before you try to use MovePrevious/MoveNext.
Related
A table in MS Access opened in Design View exposes several properties, as does the table's Property Sheet. Many of these properties are undocumented or documented only for other objects. The question is, to which object do these properties belong? Further, how does one identify them in code? Pressing F1 for context help in each case reveals no clues.
Examples include (and recognize that the names below follow from their visual context, not an object model):
Field.Description is a column in Design View (along with Field Name and Data Type) but is undocumented. Also, iterating DAO.Field.Properties reveals no Description field and references to the property fail.
Table.Description appears in the Property Sheet but also is undocumented.
Table.Filter and Table.OrderBy and their ~OnLoad counterparts appear on the Property Sheet but are documented only for other objects. I understand that information specified here is intended somehow to flow through to forms for which the table is the RecordSource, but the mechanism is not obvious and still leaves the initial question, flowing through from which object's property.
Table.LinkChildFields and Table.LinkMasterFields appear in the Property Sheet but are documented only for other objects. Also, their use in this context is not obvious.
Other table properties on the Property Sheet tell the same tale.
Any thoughts, in general or specific to any of the foregoing, would be most helpful and appreciated.
To show properties of some Access database object (table, query, form, report, ...), we can do this on VBA, defining this global function:
Function objShowProperties(ByVal xobj As Object)
Dim i As Long, varPropValue, prop As Object
On Error Resume Next
'
' loop over properties:
'
i = 0
For Each prop In xobj.Properties
varPropValue = prop.Value
'
' sometimes we have error accessing property value:
'
If (Err <> 0) Then
varPropValue = "[UNAVAILABLE]"
Err.Clear
End If
Debug.Print prop.Name, "=", varPropValue
i = i + 1
Next
On Error GoTo 0
Set prop = Nothing
objShowProperties = i
End Function
In my Acccess db I've a table named customers.
To show properties of this table, I call the above function like this:
objShowProperties CurrentDb.TableDefs("customers")
In my debug console, I got this:
All listed properties can then be accessed directly on VBA code, eg, RecordCount property:
dim lngRecords as long
lngRecords = CurrentDb.TableDefs("customers").Properties("RecordCount")
Hope this will help you.
A few things:
Field.Description is a column in Design View (along with Field Name and Data Type) but is undocumented.
No, it is not un-documented.
You are confusing DAO, and that of ms-access.
DAO "field" does not have a description property. So, it not un-documented at all.
Also in Access, there is help. You an put your cursor in the description, and hit help, and you get this:
so, place cursor here, and hit f1 for help:
And now you get this:
So, you are confusing the database engine object called DAO.FIELD with that of ms-access and it allowing you to have/enjoy/see a description in the table desinger.
I should point out that the DAO object model does not have a table designer!!!
In fact, what Access does is add's a custom property to the field, and then display's that. So, field.Description is not un-document, it in fact does not exist.
As noted in the other post here, you can "interate" all of the properties. However, if you use the database engine outside of ms-access, and EVEN create fields in code (or even by sql commands), you WILL STILL find that no descripton property exists. However, as noted, there is this thing called help, and you can give help a try, as it will explain what the description setting in ms-access does.
However, at the end of the day, field.description is not un-documented, and in fact does not exist.
so, if you read/look at/see documentaiton for the DAO field object, then these properties and options will not be found.
After all, you might be using c++, c# or some other system and that database engine that MS-Access just also happens to use.
MS-Access is not the database here. It is a tool that lets you build software, and forms and reports, and write code.
When you using MS-Access, you are not required to use the JET (now called ACE) database engine to store your data. You are free to use the Oracle database, or SQL server or whatever.
So, features of Access and things like link master fields etc.?
Those are MS-Access features, and not the database engine (ACE) features.
I've been working on an Access database for the last couple weeks, and it's my first project with the tool. Dealing with append queries seems to have become an utter nightmare, and is incredibly frustrating. Even more so because it seems to have simply stopped working in any consistent manner overnight.
The SQL query that I have written goes thus:
PARAMETERS noteDetails LongText, noteTime DateTime, srcUserID Long;
INSERT INTO tblNotes (NOTE_DETAILS, NOTE_TIME_CREATED, NOTE_SOURCE_USER)
VALUES (noteDetails, noteTime, srcUserID)
In tblNotes:
NOTE_ID is an AutoNumber
NOTE_DETAILS is a Long Text
NOTE_TIME_CREATED is a Date/Time
NOTE_SOURCE_USER is a Number
The way that I'm running this query is through VBA:
Set qdf = CurrentDb.QueryDefs("qerApndNote")
qdf.Parameters(0).Value = txtDetails.Value
qdf.Parameters(1).Value = Now()
qdf.Parameters(2).Value = getCurrentUserID()
qdf.Execute dbFailOnError
qdf.Close
Set qdf = Nothing
' Where CurrUserID is a global long
' txtDetails.Value is a textbox's contents
' Now() is the VBA built-in function to return a date/time combo
I have attempted to run this query manually from the navigation bar, and it works fine when done in that manner.
However, running it from VBA has resulted in such things as there being no time / date inserted, sometimes a user ID is not inserted, sometimes both, sometimes even the details text is missing.
What is it that I'm missing? Is there any general advice for users of MS Access to follow that I am not? I'm aware that NOTE is a restricted word in Access, but I really don't think that should apply here, right?
Thanks in advance!
EDIT: The form that I'm passing data from is called frmNewNote, and there is a control in it named txtDetails. It's just a regular textbox. Don't really know what else to share about that.
The getCurrentUserID function is in a module, modGlobal:
Public CurrUserID As Long
Public Function getCurrentUserID() As Long
getCurrentUserID = CurrUserID
End Function
Public Function setCurrentUserID(CurrID As Long)
CurrUserID = CurrID
End Function
It's about as barebones as you can get, really. And there is never a circumstance that you'll get to the form before SetCurrentUserID has been called during your... session? There's a login form involved.
#Andre's code for logging:
0 noteDetailsText This is a note test
1 noteTimeCreated 9/6/2017 10:28:45 AM
2 srcUserID 1
As for my architecture, um, it's just the single database file right now, on the desktop. The entire function/sub is run when you click a button, btnEnter. It does some other stuff before it gets to the SQL statement bit - checks for null values and prompts user for entries if that's the case.
I just remembered something:
MS Access 2013 calling insert queries from VBA with strange errors
You have a LongText parameter. These don't really work. See also https://stackoverflow.com/a/37052403/3820271
If the entered notes will always be <= 255 characters, change the parameter to ShortText.
If the text can be longer, you'll have to use either SunKnight0's approach with a concatenated INSERT statement.
Or use a Recordset and its .AddNew method, which will be a similar amount of code to your current solution, but also be completely safe from injection or formatting issues.
You are doing way more work than you have to. All you need is:
DoCmd.RunSQL("INSERT INTO tblNotes (NOTE_DETAILS, NOTE_TIME_CREATED, NOTE_SOURCE_USER) VALUES ('" & Me.txtDetails & "',Now()," & CurrUserID & ")")
Note the change from txtDetails.Value to Me.txtDetails which is what may have been messing you up. This of course assumes the code runs in the form's context, otherwise you have to get he value of the text field using a reference to the form.
The only other thing to consider is making sure Me.txtDetails does not have any single quotes, so probably use Replace(Me.txtDetails,"'","''") instead.
That way you can also replace DoCmd.RunSQL with MsgBox to troubleshoot the exact query.
I am currently half way through a project where I am migrating data from an ancient Adobe Workflow server using Visual Basic and COM.
I have hit a bit of a brick wall really as I am trying to perform a simple while loop that counts the number of records in a recordset, and I keep getting this error...
"An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in microsoft.visualbasic.dll
Additional information: Unspecified error"
There is little to no documentation to help me online so I am hoping there is some sort of VB wizard/veteran that can point me in the right direction.
I have set the record as a global variable like so...
Dim record As New EPSDK.Recordset
I have then tried...
Dim recCount As Integer = 0
Do Until record.EOF
recCount += 1
Loop
This...
Dim recCount As Integer = 0
Do While Not record.EOF
recCount += 1
Loop
This...
Dim recCount As Integer = 0
Do
recCount += 1
Loop Until record.EOF
And lots of other variations, but still cannot seem to source the problem. There are no code errors, nothing comes up in the console, and I just keep getting that message back.
Can anyone spot what I am doing wrong? Thanks
Ok, I've looked up the documentation for EPSDK. For those who are unaware (as I was), it's an object collection from Adobe for manipulating COM data. It's basically the most popular functionality in ADO.
MoveFirst, as its name suggests, moves to the first record in a recordset. There doesn't appear to be any such method supported by the EPSDK Recordset object. Since you can use the Move method to do the same thing, it isn't needed. In either case, you don't need to use it to move to the end of the file.
What you're doing wrong is expecting that you can increment a variable called recCount that you made up and the recordset cursor will magically move along. Doesn't happen. As you say, the doc is insubstantial, but you probably need to use MoveNext. Here's a cheat sheet you can use to look up what's supported.
Also, you need to specify a connection, open it, point the recordset to the open connection, and open the recordset. I would suggest that you familiarize yourself with ADO (NOT ADO.Net! Not the same thing), upon which this is clearly based. There's much more documentation, and it should apply fairly well. Read up on Connections and Recordsets in particular.
Now, your loops do pretty much the same thing. While Not is the equivalent of Until. However, if you put the while/until condition after the Do statement, you won't enter the loop unless the condition is met. If you put it after the Loop statement, you will always run the loop at least once. In this case, you should put "Do Until myRecordset.EOF", because then if the recordset is empty, you won't go into the loop.
Perhaps I've spent too much time in .NET, but it seems odd that I cannot easily pass the current Record of an ADO RecordSet to another method.
Private Sub ProcessData(data As ADODB.Recordset)
While (Not data.EOF)
ProcessRecord ([data.CurrentRecord]) ' <-- There is no CurrentRecord property.
data.MoveNext
Wend
End Sub
Private Sub ProcessRecord(singleRecord As ADODB.Record)
' Do stuff.
End Sub
The scant info I've found on the subject says to pass the entire RecordSet or to create a new Record and manually copy each field to it.
StackOverflow, is there a better way?
Personally, I would pass the entire recordset in to the ProcessRecord subroutine. Recordsets are always passed by reference so there is no overhead (performance or memory consumption) passing a recordset around. Just make sure you don't move to the next record in the ProcessRecord subroutine.
you can use the GetRows() method to load the data into an array and then let ProcessRecord work only with the array, but that 'disconnects' the method from the dataset and this may not be what you intend.
The GetRows() method takes optional arguments to specify how many rows to get, where to start and the fields to get
So:
ProcessRecord(data.GetRows(1,adBookmarkCurrent))
should do it for all fields
Unfortunately no.. you cant extract a single Record from a Recordset.. as G. Mastros said there is no additional overhead passing the whole recordset by reference and work with the current record so you might as well do it like that
I'm making a Library type app which needs to scan the whole computer when it is run for the first time. Not again ever. How can I accomplish it?
I'll be using SQL database to store data. So, I can easily make a table there and store a flag and check it on first run, but is there any other way? Any native support for this in VB.NET?
Use either
Deployment.Application.ApplicationDeployment.CurrentDeployment.IsFirstRun
or
My.Application.Deployment.IsFirstRun
Edit:
Check this article for additional info.
I found the best way to be to use appsettings..
Using your SQL database seems like a viable solution. You can also write a flag to a settings file on the file system if you don't want to use a table to hold it. This is a pretty good site with some examples on how to write to a file.
http://www.freevbcode.com/ShowCode.asp?ID=4492
EDIT: If you're looking for a way to determine, using some native feature of VB.NET, whether a method has ever been run before (as in, last year), I think you're out of luck. That said, a quick-and-dirty approach might be to define a method to query the database for the flag you've referred to and store the result of that method in a static flag.
Public Sub MethodToRunOnlyOnce()
' this flag will maintain its value between method calls '
' in the same session '
Static methodAlreadyRun As Boolean = MethodHasBeenRun()
If methodAlreadyRun Then
Exit Sub
End If
Try
' ... code ... '
Finally
MethodToSetDatabaseFlag()
methodAlreadyRun = True
End Try
End Sub
Private Sub MethodToSetDatabaseFlag()
' code here to set Db flag '
End Sub
Private Function MethodHasBeenRun() As Boolean
' code here to check Db flag '
End Function
You could always store this flag in an xml file or in the registry so it's on the PC. If you store it in a database and there are multiple copies of this program running on different PCs, you would have to identify them in the DB somehow, whereas if you keep track of it locally you don't need to worry about it.