VB6 recordset code to VB.Net - vb.net

I am updating someone elses old code from a VB6 windows application to a VB.Net web application. I understand the old code, but I am not sure how I would translate it to .Net recordsets.
myStoredProcedure = "sp_WritevPayrollCurrent"
myCurrentPast = "'N'"
myStoredProcedure = "sp_ObtainSubClassID"
myClassName = "Payroll Major"
mySubClassName = "New Hire"
Set rs = TgetReadResultsetWithParms(myClassName, mySubClassName, (myStoredProcedure))
Also, I am not sure what will happen with "myStoredProcedure" being declared twice or could that be an error?
The TgetReadResultsetWithParms function is as follows (some Cases redacted to free up space):
Dim en As rdoEnvironment
Dim cn As rdoConnection
Dim rq As rdoQuery
rdoDefaultCursorDriver = rdUseServer
'open a connection to the tstdbexecutive database using DSNless connections
Set en = rdoEnvironments(0)
Set cn = connectionstring stuff here
Select Case myStoredProcedure
'create reusable rdoQuery and Call SQL server stored procedure.
Case "sp_ObtainClassID"
Set rq = cn.CreateQuery("", "{call " & cstDatabaseName & ".dbo.sp_ObtainClassID(?)}")
Case Else
Set rq = cn.CreateQuery("", "{call " & cstDatabaseName & ".dbo." & myStoredProcedure & "(?)}")
End Select
'set the input argument value for the store procedure.
rq(0) = myParm1
'open the Resultset and pass it back to calling procedure
Set TgetReadResultsetWithParm = rq.OpenResultset(rdOpenKeyset, rdConcurReadOnly)

The VB6 code is using Remote Data Objects. I think you will have to read the documentation to understand what the VB6 is doing, and then rewrite in VB.Net using ADO.Net to achieve the same functionality. AFAIK there is no handy cheat-sheet which shows how RDO compares with ADO.Net, unfortunately. There are some for ADO-ADO.Net.
Alternatively you could add a reference to Remote Data Objects in your .Net project - you can use COM objects in .Net - and then use the same code. If there is a large amount of the old code, this could be a pragmatic way to make the task more manageable, although it makes the code harder to understand for other programmers who would probably be used to ADO.Net. It's better to rewrite if you can afford to.

Related

Additional information: There is already an open DataReader associated with this Command which must be closed first. vb.net

Dim cat As New Catalog()
Dim con As New OleDbConnection()
Dim cmd As New OleDbCommand
Dim ds1 As New DataSet
Dim conn As ADODB.Connection
' Open the Access database.
conn = New Connection
conn.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;" &
"Data Source=" + openExcel + "\Test" + ".mdb; Persist Security Info=False"
con.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;" &
"Data Source=" + openExcel + "\Test" + ".mdb; Persist Security Info=False"
conn.Open()
xlWorkSheet1.Columns(5).Insert
Dim cellValue As String = ""
Dim newValue As String = ""
Dim sh1 As String = ""
Dim qty As String = ""
Dim matchText As String = ""
Dim sql As String = ""
con.Open()
sh1 = LTrim$(xlWorkSheet1.Cells(i, 1).Text)
sql = "SELECT Num_ber, Q_ty FROM good WHERE Na_me LIKE 'staff%' And Ty_pe = 'ORD'"
Dim cmd As New OleDbCommand(sql, con)
Dim myReader As OleDbDataReader = cmd.ExecuteReader()
conn.Execute(sql)
myReader = cmd.ExecuteReader() ' HERE'S THE PROBLEM
xlWorkSheet1.Cells(1, 5) = myReader.GetString(0)
xlWorkSheet1.Cells(1, 11) = myReader.GetString(1)
myReader.Close()
conn.Close()
conn = Nothing
**I wanted to retrieve a specific value from mdb and then write it to excel.
Here's my code, I got this error so many times and I can't find it out. Can anybody help me? Thanks.**
[1]: https://i.stack.imgur.com/6Fuvg.png
Ok, you first have to decide when usng .net what "provider" you are going to use, AND THEN decide what kind of data objects you want to use.
You can use a oracle provider, a sql server provider, or in this case, since we using Access, then we can use EITHER oleDB, or ODBC. Either choice is fine. Most use oleDB providers for Access, but often ODBC is a good choice, especially if down the road you plane to swap out Access for say SQL server.
What the above means in plain English?
You don't want to adopt the external ADODB code and library. That code is NOT .net, and thus you REALLY but REALLY do not want to write your .net code that way. ADODB was written LONG before .net, and is what we call un-managed code (non .net). I strong, but strong suggest you do NOT add a reference to ADODB to your project, and I beyond strong recommend you avoid introduction of a non .net library for doing this!!! We certainly can adopt the oleDB provider in .net, but we will NOT have a direct reference to JET/ACE (the access database engine) in our applcation. As noted, there are some exceptions to this suggesting, but they don't apply to you and here.
Next up:
The design pattern in .net is to create the connection, get the data, and CLOSE the connection. This "pattern" will then be 100% sure that the data base is always closed, and you NEVER have to worry about if the connection is open, closed, or even if you forgot to close the connection!!! So, do this correct, and some "open" connection will never bite you, or will you have to worry about this issue.
You can in some operations keep the connection open for performance, but lets learn to walk before we run so to speak.
next up:
We certainly do NOT want to place and have connection strings all over in our code. Not only is this going to wear out your keyboard, but if you ever need to change the connection, then you going to have to hunt down all that code.
Best to let Visual Studio save that connection in ONE location, and MORE important MANAGE this for you!!!
Next up:
Do you ONLY need to work with mdb files, or do you plan/need to work with accDB files? This is a HUGE issue, and one that you cannot ignore.
next up:
Are you going to use the x32 bit version of the Access database system, or the x64 bit version?
Since your example posted code uses JET (access data engine for mdb files ONLY x32 bit version)?
Then this ALSO means you MUST (and I repeat MUST) force your .net project to run as x32 bits. You cannot use "any cpu", and you cannot use x64 bits, you MUST choose x86 bit size for your .net project. Failure to do so will result in the project not working.
Ok, with the above information?
First up, force/set/be 100% sure your project is set to run as x32 bits.
That setting is this one:
and remove the reference you have to ADO if you created one.
Ok,
next up:
Create the connection to the database.
Project ->properties.
This here:
And then:
and then
Now, you can browse, and select the access mdb file.
But, you MUST not skip the next step - you have to choose JET (older, mdb files), or choose the newer ACE (for accDB format files).
So, this:
now this:
As noted, you choose JET or ACE here.
now, we have this and you can use test connection.
BUT BE VERY careful!!!!
If you are using vs2022, then keep in mind vs2022 is the FIRST version of VS that is now x64 bits. As a result, vs can't pass the test connection!!! Your connection is in fact ok, but will fail with vs2022.
If you using a previous version of VS (before 2022), then the test connection button should work. and you see this:
Ok, now that we have a valid working conneciton setup, we can now write code, and we will NOT use ADODB!!!!
The typical code pattern to read and load a data table (like a access VBA recordset) will be like this:
Now, I became RATHER tired of writing that same using block over and over. So, in a global module, I have this code now:
Public Function MyRst(strSQL As String) As DataTable
Dim rstData As New DataTable
Using conn As New OleDbConnection(My.Settings.AccessDB)
Using cmdSQL As New OleDbCommand(strSQL, conn)
conn.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rstData
End Function
So, now with the above handy dandy helper routine?
Your code becomes this:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim Sql As String =
"SELECT Num_ber, Q_ty FROM good WHERE Na_me LIKE 'staff%' And Ty_pe = 'ORD'"
Dim rstData As DataTable = MyRst(Sql)
Debug.Print("Na_me is " & rstData.Rows(0).Item("Na_me"))
End Sub
Or, display all return rows from that data table
Debug.Print("Na_me is " & rstData.Rows(0).Item("Na_me"))
For Each OneRow As DataRow In rstData.Rows
Debug.Print("na_me = " & OneRow("Na_me"))
Next
So, you really don't need (or want) a reader anyway. Just load the results into a nice clean, easy to use data table, and from that you can loop the table, grab rows, or do whatever you want.

MS Access crashes binding RS to a form from SQL Server stored procedure

I am just starting to move our Access DB to SQL Server and am having trouble.
I have a stored procedure that successfully returns rows to an ado recordset.
When I try to bind the rs containing the results of the stored procedure to the Access form, Access crashes without displaying any error messages. I'm on O365 32b and SQL Server 2019.
Here's the code:
Dim sSQL As String, rs As ADODB.Recordset
1 sSQL = "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
2 ADOConn.ConnectionString = conADO
4 ADOConn.Open
6 Set rs = New ADODB.Recordset
7 rs.CursorLocation = adUseClient
8 rs.Open sSQL, ADOConn
10 Set Me.Recordset = rs ' Access crashes here
. . .
Any help would be greatly appreciated!
tia.
SR
Ok, are you previous using ADO, or are you just introducing this?
In most cases, you are better off to just use a view. (replace the access query with a linked view), and then continue useing client side where clauses or filters (access will ONLY pull down the rows you request). So linked views are often a better choice and much less work (in fact, even existing filter for a open report etc. will work and only critera matching the were clause records are pulled.
And in most cases, i don't introduce ADO.
So for a PT query, I often do this:
dim rs as DAO.RecordSet
with CurrentDb.queryDefs("qryPt")
.SQL = "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
set rs = .OpenRecordSet
end with
So, above assumes you have a pt query called qryPt. This also means that you never deal with or worry about connection strings in code. The pt query has the connection. (and your re-link code now can re-link tables and pt queries).
I ONLY suggest the above as a FYI in case that you introducing ADO for calling store procedures, and the rest of the application was previous DAO. If the application was previous DAO, then leave it alone, and use above approach for your PT queries - even code that needs to call store procedures.
Access tends to try and parse the query text to get filters/sorts/etc to work, and if it isn't a plain syntax error but isn't Access SQL either, strange things tend to happen, mostly crashes.
Try adding a comment up front to make sure Access knows not to parse:
sSQL = "-- Access no parse pls" & vbCrLf & "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
The content of the comment is not relevant, of course, its purpose is to immediately cause a syntax error when Access tries to parse it as Access SQL (which doesn't have comments)

Visual FoxPro-query with parameters

Do somebody know how can i write in SQL language in Visual FoxPro a query with parameters? It doesn't work in the same way like it does in Access and I am a little bit lost here.
Thank you in advance!
Unfortunately your question is too broad to provide a simple answer.
The syntax for one query will vary from the syntax to perform a different query.
And Yes, the SQL Query syntax is likely slightly different than M$ Access.
However you can always do a Google search for: vfp sql query syntax to find specific syntax equivalents.
Note: The "WITH" parameters will be in a simple WHERE clause similar to most other SQL Query languages,
Such as WHERE Field1 = "ABC" AND Field2 = 235
but it will be using the VFP language syntax.
Also you might want to spend some time looking at the free, on-line VFP tutorial videos at: free on-line VFP tutorial videos
Specifically the one labeled: FoxPro and the SQL Language
You can visit w3schools.com to see SQL basics. It doesn't work like access, that is true, because access, which is a so called SQL database engine, has its own understanding of the SQL. VFP OTOH is closer to ANSI SQL (IOW closer to SQL Server).
You haven't specified the language you are using, but saying access, I would assume you are trying with VBA. Here is a sample in VBA (excel) using parameters:
Sub Macro1()
Dim oRecordset1 As ADODB.Recordset
Dim oConnection As ADODB.Connection
Dim oCommand As ADODB.Command
Dim oParameter1 As ADODB.Parameter
Dim oParameter2 As ADODB.Parameter
Set oConnection = New ADODB.Connection
Set oCommand = New ADODB.Command
oConnection.ConnectionString = "Provider=VFPOLEDB;Data Source=C:\Program Files (x86)\Microsoft Visual FoxPro 9\Samples\Northwind"
oConnection.Open
oCommand.ActiveConnection = oConnection
oCommand.CommandText = "select * from Orders where OrderDate >= ? and OrderDate < ?"
Set oParameter1 = oCommand.CreateParameter("start")
oParameter1.Type = adDate
oParameter1.Value = CDate("1996-08-01")
oCommand.Parameters.Append oParameter1
Set oParameter2 = oCommand.CreateParameter("end")
oParameter2.Type = adDate
oParameter2.Value = CDate("1996-10-01")
oCommand.Parameters.Append oParameter2
Set oRecordset = oCommand.Execute()
Sheet1.Range("A1").CopyFromRecordset (oRecordset)
End Sub
Note: Parameters are positional, not named.
It depends on what kind of query you're using, either using the built-in SQL engine that queries native FoxPro tables or if it's a query using an external data source.
First for the case of a native query, it's really simple. Since it's a native FoxPro instruction, you can access to every single feature out there, including variables, where you can simply put your user supplied data without worries:
LOCAL data &&This could come from user input
data = "hello world"
SELECT * FROM SomeTable WHERE Column = data &&Filtered parametrized query
The other option is to submit a SQL query for an external server to process, where the query is sent as a text string. In this case, special markers for parameters can be used, matching FoxPro variables, and in turn that would result in a parametrized query sent to the server:
LOCAL data
data = "hello world"
LOCAL hConn = SQLSTRINGCONNECT(connectionString)
SQLEXEC(hConn, "SELECT * FROM SomeTable WHERE Column = ?data", "SomeTable") &&The "?data" parametrizes the query, sending the value separate from the query itself
SQLDISCONNECT(hConn)

Can I create a pass-through query via VBA to call a parameterized tSQL UDF and send it a dynamic parameter to return results to Access?

I currently have a SQL 2008 R2 database backend with an Access 2013 accdb front end with ODBC DSN-less connection and linked tables. In SQL I have many parameterized tSQL UDFs created to feed data into reports (currently working well in my Access 2010 adp frontend). The reports are complicated: multiple tSQL UDFs run calculations and then feed into a final UDF that feeds the respective report. I would like to keep the UDFs on the server – rewriting into Access queries would be a poor solution.
My problem is that I have not been able to figure out how to write the VBA correctly to send a pass-through query to call the tSQL UDF and give it a parameter, which would change for each report. I know pass-through queries are read-only, that’s ok. I’ve read that I can call a stored procedure (SP) from VBA, but can I call the UDF rather than having to convert each to a SP or create a SP just to call the UDF so that I could call the SP from VBA. Based on my research, I think I might have to either create a SP to call the UDF or convert the UDF to a SP to get the VBA to work (i.e., return results without error). Is this correct?
I found this discussion: https://social.msdn.microsoft.com/Forums/office/en-US/898933f5-73f9-44e3-adb9-6aa79ebc948f/calling-a-sql-udf-from-access?forum=accessdev , but it has conflicting statements “You can't call a tSql udf from Access.”, and “You can use a passthrough query to call UDF's or stored procedures or anything else written in tsql.” Also, their code is written in ADO instead of DOA so it’s a bit cryptic to me since I’ve only written DAO so far, but the general gist that I got was they converted their UDF to a SP.
I found this article a great read, but again did not get a clear “yes” to my question:
http://technet.microsoft.com/en-us/library/bb188204(v=sql.90).aspx
It may be possible to remove the parameter from the Server side and add it to the Access side similar to this Access 2007 forms with parameterized RecordSource , but wouldn't that cause Access to load the entire dataset before filtering, instead of processing on the Server side – possibly causing performance issues?
I can successfully create a pass-through query in the Access interface if I supply it with a constant parameter, for example “Select * from udf_FinalReport(2023)”, but what I really need is to be able to pass a dynamic parameter. For example, the parameter would be from Forms!Control![txtboxValue]. Can I do this? The following code is what I’m using– it works if I use a table name in the SQL (ex, “SELECT * FROM Table WHERE tblYear = “&intYear ) in line 9 so I feel like I have everything coded right, but when I put my UDF in the SQL like below I get the error #3131 “Syntax error in FROM clause.” (I did verify that I should not use the prefix schema (dbo.) – this gives error 3024 “could not find file”.) Is this user error or just plain telling me I can’t call a UDF this way?
1 Sub AnnualSummary()
2 Dim dbs As DAO.Database
3 Dim qdfPoint As DAO.QueryDef
4 Dim rstPoint As DAO.Recordset
5 Dim intYear As Integer
6 intYear = Reports!Annual_Delineation_Summary!txtYear
7 Set dbs = OpenDatabase("", False, False, "ODBC;DRIVER=sql server;SERVER=******;APP=Microsoft
8 Office 2010;DATABASE=*******;Network=DBMSSOCN")
9 Set qdfPoint = dbs.CreateQueryDef("", "Select * from udf_AnnualReport(" & intYear& ")")
10 GetPointTemp qdfPoint
11 ExitProcedure:
12 On Error Resume Next
13 Set qdfPoint = Nothing
14 Set dbs = Nothing
15 Set rstPoint = Nothing
16 Exit Sub
17 End Sub
18
19 Function GetPointTemp(qdfPoint As QueryDef)
20 Dim rstPoint As Recordset
21 With qdfPoint
22 Debug.Print .Name
23 Debug.Print " " & .SQL
24 Set rstPoint = .OpenRecordset(dbOpenSnapshot)
25 With rstPoint
26 .MoveLast
27 Debug.Print " Number of records = " & _
28 .RecordCount
29 Debug.Print
30 .Close
31 End With
32 End With
33 End Function
I also tried writing the code a little differently, using the following instead of lines 5, 6, and 9. This also works when I use a table name in the select statement, but I get error #3131 when I use a UDF name:
Set qdfPoint = dbs.CreateQueryDef("", "Parameters year int; Select * from Point_Info where
year(Sample_Date) = year")
qdfPoint.Parameters("year").Value = intYear
Both code variations also work if I try use the name of a SQL View in the tSQL SELECT statement.
My consensus is using ADO language instead of DAO to write the pass-through query works well. But, I have found that it is still probably better to execute a stored procedure than to try to call the UDF. Here is the code that ended up working most smoothly for me: (my ADO Connection uses Public variables strUID and strPWD)
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim strPoint As String
strPoint = Forms!FRM_Vegetation_Strata!Point_ID
Set cn = New ADODB.Connection
cn.Open "Provider = sqloledb;Data Source=imperialis.inhs.illinois.edu;" & _
"Initial Catalog=WetlandsDB_SQL;User Id=" & strUID & ";Password=" & strPWD
Set rs = New ADODB.Recordset
With rs
Set .ActiveConnection = cn
.Source = "sp_Report_VegWorksheet '" & strPoint & "'"
.LockType = adLockOptimistic
.CursorType = adOpenKeyset
.CursorLocation = adUseClient
.Open
End With
Set Me.Recordset = rs
On a side note I found that to get set the .Recordset to fill a subform put this code in the "Open" event of the subform.
Then to clean up your connection:
Private Sub Form_Unload(Cancel As Integer) 'use "unload", not "close"
'Close the ADO connection we opened
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Set cn = Me.Recordset.ActiveConnection
cn.Close
Set cn = Nothing
Set rs = Nothing
Set Me.Recordset = Nothing
End Sub
This approach does not work for populating a report. "Set Me.Recordset" only works for forms. I believe I will have to call a stored procedure then populate a temp table to use as the report recordset.
EDIT: I have found that I can call a SQL UDF or SP from VBA in Access using DOA. This is particularly helpful when one wants to pull the data from a complicated SQL function/procedure and put it into an Access-side temp table. See Juan Soto's blog https://accessexperts.com/blog/2012/01/10/create-temp-tables-in-access-from-sql-server-tables/#comment-218563 This code puts the info into a temp table, which is what I wanted to populate my reports. I used his code example and the following to call the sub:
To execute as SP: CreateLocalSQLTable "testTBL","exec dbo.sp_Report_WetDet_point '1617-1-1A'",False
To call a UDF: CreateLocalSQLTable "testTBL","Select * from dbo.QryReport_Main('1617-2-2A')",False
I don't know if it's the most efficient method of passing a variable parameter through a pass-through query into a function and returning the results to Access, as I am still relatively new to Access, but I came across this earlier when I was attempting a similar problem.
I managed it by creating a couple of pass-through queries that executed functions in SQL server and returned a result. I then made a small VBA script that re-wrote the pass-through queries with the new variable every time I wanted to change it, and executed them.
I got the result back out using OpenRecordset, and stored it as a string to use in the rest of my code.

Is there a VB.NET equivalent of PrivateDBEngine from VB6?

Hi I don't have experience with VB6 or VB.NET but am trying to convert some old code to .NET. The VB6 uses PrivDBEngine.
Public oDbEngine As New PrivDBEngine
After some googling this looks like DAO. I was told to replace its usage with ADO.NET. I pasted every spot I see it in the code below as a reference in case it helps. I'll get to googling "PrivateDBEngine DAO to ADO.NET" but if anyone knows of an equivalent in ADO.NET or even has some useful links please let me know. Should I be looking into DataSet? Thank you very much for your time and patience. Other places I encounter it are:
' Build the proper connection string. If ODBC, the
' options line of the OpenDatabase method accepts the
' connection string. If Access, just pass in the
' filename
sPassword = Password
Select Case ConnType
Case DBTYPE_ACCESS
DBFilename = ConnectString
If (Len(UserName) = 0 And Len(Password) <> 0) Then
DBOptions = ";PWD=" + Password
sPassword = ""
Else
DBOptions = ""
End If
If (UserName = "") Then
UserName = "Admin"
Else
UserName = UserName
End If
If (Len(SystemMDB) <> 0) Then
---> oDbEngine.SystemDB = SystemMDB <-----------
End If
And also:
' Handle UserName and Password.
Set oWorkSpace = oDbEngine.CreateWorkspace("Test", UserName, sPassword)
And lastly:
Sub CleanUpDBConnection()
On Error Resume Next
' Close the recordsets
grsIndexTable.Close
grsDocTable.Close
' Close the database
If Connected Then
DBConnection.Close
Set DBConnection = Nothing
oWorkSpace.Close
Set oWorkSpace = Nothing
Set oDbEngine = Nothing
CurrentDTable = ""
CurrentITable = ""
Connected = False
End If
End Sub
PrivDBEngine is part of DAO. It's similar to DBEngine.
In an application, you may need to connect to multiple databases with different workgroup security connections. The PrivDBEngine lets you do that separate from DBEngine.
A common scenario is the main database (connected via DBEngine) which has data pointing to other databases, each with their own workgroup security settings. In that case, PrivDBEngine would be use to open those databases.
Off the top of my head, I can't remember if you can support 3 workgroup security settings at one time, but you can certainly reset the PrivDBEngine variable as needed without impacting all the recordsets already open using the DBEngine variable.
You should use the same ACE/DAO/DBEngine code in VB.NET if you are using Access databases. ADO can replace some ACE/DAO code, especially if you're using SQL Server and just retrieving data, but if you're using Access databases, ACE/DAO supports features that ADO doesn't.