How to use If .eof OR .bof condition in vb.net? - vb.net

I am converting vb6 application into vb.net and in it .eof and .bof are used as condition. I am not understanding how to carry out these conditions in vb.net
sSql = "Select * From SPCsetup"
Set dbConn = New ADODB.Connection
Call openDBconn(dbConn)
Set rsConn = dbConn.Execute(sSql)
If rsConn.EOF Or rsConn.BOF Then
bFlag = False
Else
bFlag = True
End If

Well, first off, ADODB is a COM component so you could in theory just keep on using it. But it’s not really recommended as while it does have some beers and whistles they are not without their own problems. Ado.Net exist for a reason and it’s not just because they like writing new code to do the same thing.
Secondly if you use a datareader then bof (before first record) is somewhat relevant, but if you use a dataadapter to fill a table it’s not. It either has records or it doesn’t. If you want/need to continue using something like a record set, then that would be a datreader...there isn’t a BOF, but you don’t really need it. You find out nothing was returned, by the fact that nothing was returned.
sSql = "Select * From SPCsetup"
Using dbConn = New SqlConnection(connctionString)
dbConn.Open()
Using dbCmd = dbConn.CreateCommand()
dbCmd.CommandText = sSql
Using dbReader = dbCmd.ExecuteReader
bFlag = false
While dbReader.Read
bFlag = true
'Do something
End While
End Using
End Using
End Using

As noted from your other posts, you can (and should) do one of two things:
Create your own recordset class. It will take likely less then 30 minutes. You can then use your existing code with VERY little changes.
And you ALSO really (but really really) needed to share with everyone here WHAT KIND of data object you going to use, or are planning to use or are currently using in vb.net. (or ASK what kind of data object you should use).
Are you using a dataset?
Are you using a datatable?
Are you using a iList?
.net has a GAZZILLION choices, ranging from “iList”, and a bunch more I NOT listed out here. So we have little clue as to WHAT you currently using.
I am going to take a BIG FAT WILD guess and assume datatable.
Assuming we using a datatable, then you code would be something like:
Dim tblHotels As New DataTable
Dim strSQL As string = "select * from tblHotels"
Dim DataReader As New SqlDataAdapter(strSQL, My.Settings.SQLCon1string)
DataReader.Fill(tblHotels)
If tblHotels.Rows.Count = 0 Then
bFlag = False
Else
bFlag = True
End if
So, in place of
If tblHotels.EOF then
You would then have:
If tblHotels.Rows.Count = 0 Then

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.

Read Value from Database in TextBox when Combobox text changes VB.NET

I have a list of Users Names in ComboBox and Some TextBoxes. When ComboBox text changes (i.e I select some username from ComboBox), The TextBoxes are filled with user details from the database.
I have code to achieve this in SQL Database. But these queries are not working with MsAccess database.
MysqlConn = New MySqlConnection
Mysql.ConnectionString = "server=localhost;user=root;password=root;database=database"
Dim READER As MySqlDataReader
Try
MysqlConn.open()
Dim Query As String
Query("select * from database.usernames where name='" & ComboBox1.Text & "'")
Command = New MySqlCommand(Query, MysqlConn)
READER = Command.ExecuteReader
While READER.Read
TextBox1.Text = READER.GetString("name")
End While
End Try
Here is my answer. Please don't get overwhelmed by it. ;)
Broken code
First of all, as I see it, the code you provided cannot work at all, because:
your Query variable is initialized in an invalid (or at least a very exotic) way. You probably want to use something like:
Dim Query As String
Query = "select * from database.usernames where name='" & ComboBox1.Text & "'"
or in a single line:
Dim Query As String = "select * from database.usernames where name='" & ComboBox1.Text & "'"
you try to assign the connection string to the ConnectionString property of a nonexistent Mysql variable. Or the variable exists because it is declared somewhere else, which might be a bug in your code snippet here. But I assume you want to assign the connection string to the MysqlConn.ConnectionString property instead.
you have not declared the MysqlConn and Command variables anywhere. You only just assign to them. (I will simply assume you have declared the variables correctly somewhere else in your code...)
the IDataRecord interface does not provide a GetString(name As String) method overload. So unless you have defined a custom extension method for it, you probably need to use the IDataRecord.GetOrdinal(name As String) method as well, or use the column index instead of the column name.
Anyway, the code you provided uses MySQL. So I assume that MySQL is the "SQL Database" you are using successfully. And that seems to work, as you say? Well... Hmmm... Then I will simply assume your code snippet is completely correct and works perfectly with MySQL... :/
MS Access vs. MySQL
Using MS Access requires other data access classes (probably the ones in namespace System.Data.OleDb) and another connection string. You could take a look at this ADO.NET OleDb example for MS Access in the Microsoft documentation.
You probably even have to update your SQL query, because every database system uses its own SQL dialect. You might want to consult the Office documentation for that. But your query is quite simple, so perhaps all you have to do to make it work with MS Access is:
remove the database name and use only the table name, and
delimit the name identifier (since it is a reserved keyword in MS Access).
I personally delimit all identifiers in my SQL queries, just to avoid unintended conflicts with reserved keywords. So I would personally use something like this:
select * from [usernames] where [name] = '...'
Additional tips
Also, I would like to provide you some additional (unrelated) tips regarding improving your code:
Use Using-statements with variables of an IDisposable type as much as possible. Those types/classes do not implement that interface if there isn't a good reason for it, so I consider it not unimportant to call Dispose when you are done with such disposable objects (or using a Using statement to call Dispose implicitly).
Use SQL parameters (if possible) to avoid SQL injection vulnerabilities. Look at this StackOverflow question and its answer for an example of how to use SQL parameters with MS Access.
Example
You may take a look at the following code snippet. It might not provide a working example out-of-the-box, but you might get some useful/practical ideas from it:
Dim connectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\Data\\database.mdb;User Id=admin;Password="
Dim query As String = "select * from [usernames] where [name] = #Name"
Using conn As New OleDbConnection(connectionString)
Using command As New OleDbCommand(query)
command.Parameters.Add("#Name", OleDbType.VarChar, 50).Value = ComboBox1.Text
conn.Open()
Using reader As OleDbDataReader = command.ExecuteReader
If reader.Read Then
textbox1.Text = reader.GetString(reader.GetOrdinal("name"))
End If
End Using
End Using
End Using

Is there a better way to avoid error when using ADODB.Command with parameters?

I had some existing VBA code that was building queries using string concatenation. I updated the code to use a command object with a parameter instead, but then started getting an error every once in a while that said String data, right truncation. After looking into it, I found out that if my collection of strings started with a string smaller than the rest, it would fail when it got to a longer string. To make it work, I just added some code to sort the collection from largest to smallest. Easy enough for this example since I know I won't have more than a few strings, but if I ever have a larger collection of strings, it might be an issue.
Is there any other way around this besides sorting the collection? Below is the section of code that causes the issue.
Dim lineNumbers As New Collection
Dim cnDb as new ADODB.Connection
Dim cmd as new ADODB.Command
Dim rs as new ADODB.RecordSet
lineNumbers.Add "001-3""-5116323-ABA"
lineNumbers.Add "001-1""-5116327-ABA-1 1/2""C" ' If not sorted, it fails when it tries this one
lineNumbers.Add "001-1""-5116327-ABA"
lineNumbers.Add "001-1""-5116327-ABA-1""C"
sQry = "SELECT COUNT(commondatalink) FROM commondata WHERE reportedlineno = ?"
cmd.ActiveConnection = cnDb
cmd.CommandText = sQry
cmd.CommandType = adCmdText
For i = 1 To lineNumbers.Count
Set rs = cmd.Execute(, Array(lineNumbers(i))) ' Error thrown here on unsorted list
If rs(0) > 1 Then
' do something...
End If
Next i
Seems like you can't re-use a command object like that: first time it runs it may infer the parameter type/length, and if a subsequent call uses a longer value that triggers the error.
You could try explicitly creating the parameter using cmd.CreateParameter() and setting the size to the size of the field being queried (or a little larger)

VB.NET Appending table to a database from DataTable object

I am trying to convert some old VB6 code into VB.NET. The old code used DAO and now I am trying to replicate it in ADO.NET/OleDB. I have made some advances (I think...) but now I can't figure out how to add the DataTable object into the database.
Here is the old VB6 code, td is a TableDef object from DAO:
If fso.FileExists(loc) Then
Set td = m_db.CreateTableDef("Ratings")
td.Connect = "Excel 8.0;HDR=Yes;IMEX=2;DATABASE=" & loc
td.SourceTableName = "Sheet1$"
m_db.TableDefs.Append td
bFileNotExists = False
Else
bFileNotExists = True
End If
From what I understand this is reading Sheet1 from the Excel file 'loc' and then appending it to m_db, a DAO database object. This is what I have so far, and please correct me if you see any mistakes as I'm just getting started with this sort of thing -
If fso.FileExists(loc) Then
oleCon = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & loc & ";Extended Properties=""Excel 8.0;HDR=Yes;")
oleCon.Open()
oleAdapter = New OleDbDataAdapter("SELECT * FROM [Sheet1$]", oleCon)
oleAdapter.Fill(dt)
bFileNotExists = False
Else
bFileNotExists = True
End If
So instead of the TableDef, I am taking the data from the same sheet and putting it in a DataTable object (dt). I hope this is correct so far. Now my question is how to replicate the m_db.TableDefs.Append td line from above. Thank you!
The thing is, that you have to pre-load the 'dt' with the configuration in the Excel-file, in order for the TableAdapter to work out. This is as far as I know. There's many paths you can take, including first creating columns and then loading row-by-row, or loading the Excel-sheet in as a DataTable itself and add this to a DataSet.
Suggestions:
Start using CamelCase programming notation. This really helps out and prevents errors.
Read up on ADO.NET, for example by following some tutorials.
Drop OleDb handling, ADO.NET suffices.
Realize the differences between VB.Net and VB6, and prepare to learn some more object-oriented programming

Query Tables (QueryTables) in Excel 2010 with VBA with VBA creating many connections

I'm following code I found on another site. Here's the basics of my code:
Dim SQL As String
Dim connString As String
connString = "ODBC;DSN=DB01;UID=;PWD=;Database=MyDatabase"
SQL = "Select * from SomeTable"
With Worksheets("Received").QueryTables.Add(Connection:=connString, Destination:=Worksheets("Received").Range("A5"), SQL:=SQL)
.Refresh
End With
End Sub
The problem with doing this is every single time they hit the button assigned to this it creates a new connection and doesn't ever seem to drop it. I open the spreadsheet after testing and there are many versions of the connection listed under Connections.
Connection
Connection1
Connection2
I can't seem to find a way to close or delete the connections either. If I add ".delete" after ".Refresh" I get a 1004 error. This operation cannot be done because the data is refreshing in the background.
Any ideas how to close or delete the connection?
You might ask yourself why you're creating a QueryTable every time in your code. There are reasons to do it, but it usually isn't necessary.
QueryTables are more typically design-time objects. That is, you create your QueryTable once (through code or the UI) and the you Refresh the QueryTable to get updated data.
If you need to change the underlying SQL statement, you have some options. You could set up Parameters that prompt for a value or get it from a cell. Another option for changing the SQL is changing it in code for the existing QueryTable.
Sheet1.QueryTables(1).CommandText = "Select * FROM ...."
Sheet1.QueryTables(1).Refresh
You can select different columns or even different tables by changing CommandText. If it's a different database, you'll need a new connection, but that's pretty rare.
I know that doesn't answer your question directly, but I think determining whether you really need to add the QueryTable each time is the first step.
For more on Parameters, see http://dailydoseofexcel.com/archives/2004/12/13/parameters-in-excel-external-data-queries/ It's for 2003, so there are few inconsistencies with later versions. The basics are the same, you just may need to learn about the ListObject object if you're using 2007 or later.
I had the same issue. The previous answer while a definite step in the right direction is a PITA.
It did however allow me to refine my search and the winner is...
http://msdn.microsoft.com/en-us/library/bb213491(v=office.12).aspx
i.e. for your existing QueryTable Object just do this:
.MaintainConnection = False
Works ever so swell. No more Access DB lock file after the data is refreshed.
You should declare the connection as a separate object then you can close it once the database query is complete.
I don't have the VBA IDE in front of me, so excuse me if there are any inaccuracies, but it should point you in the right direction.
E.g.
Dim SQL As String
Dim con As connection
Set con = New connection
con.ConnectionString = "ODBC;DSN=DB01;UID=;PWD=;Database=MyDatabase"
Worksheets("Received").QueryTables.Add(Connection:=con, Destination:=Worksheets("Received").Range("A5"), SQL:=SQL).Refresh
con.close
set con = nothing
I've found that by default new connections created this way are called "Connection". What I am using is this snippet of code to remove the connection but retain the listobject.
Application.DisplayAlerts = False
ActiveWorkbook.Connections("Connection").Delete
Application.DisplayAlerts = True
It can easily be modified to remove the latest added connection (or if you keep track of the connections by their index).
Application.DisplayAlerts = False
ActiveWorkbook.Connections(ActiveWorkbook.Connections.Count).Delete
Application.DisplayAlerts = True
Instead of adding another query table with the add method, you can simply update the CommandText Property of the connection. However you have to be aware that there is a bug when updating the CommandText property of an ODBC connection. If you temporarily switch to an OLEDB connection, update your CommandText property and then switch back to ODBC it does not create the new connection. Don't ask me why... this just works for me.
Create a new module and insert the following code:
Option Explicit
Sub UpdateWorkbookConnection(WorkbookConnectionObject As WorkbookConnection, Optional ByVal CommandText As String = "", Optional ByVal ConnectionString As String = "")
With WorkbookConnectionObject
If .Type = xlConnectionTypeODBC Then
If CommandText = "" Then CommandText = .ODBCConnection.CommandText
If ConnectionString = "" Then ConnectionString = .ODBCConnection.Connection
.ODBCConnection.Connection = Replace(.ODBCConnection.Connection, "ODBC;", "OLEDB;", 1, 1, vbTextCompare)
ElseIf .Type = xlConnectionTypeOLEDB Then
If CommandText = "" Then CommandText = .OLEDBConnection.CommandText
If ConnectionString = "" Then ConnectionString = .OLEDBConnection.Connection
Else
MsgBox "Invalid connection object sent to UpdateWorkbookConnection function!", vbCritical, "Update Error"
Exit Sub
End If
If StrComp(.OLEDBConnection.CommandText, CommandText, vbTextCompare) <> 0 Then
.OLEDBConnection.CommandText = CommandText
End If
If StrComp(.OLEDBConnection.Connection, ConnectionString, vbTextCompare) <> 0 Then
.OLEDBConnection.Connection = ConnectionString
End If
.Refresh
End With
End Sub
This UpdateWorkbookConnection subroutine only works on updating OLEDB or ODBC connections. The connection does not necessarily have to be linked to a pivot table. It also fixes another problem and allows you to update the connection even if there are multiple pivot tables based on the same connection.
To initiate the update just call the function with the connection object and command text parameters like this:
UpdateWorkbookConnection ActiveWorkbook.Connections("Connection"), "exec sp_MyAwesomeProcedure"
You can optionally update the connection string as well.
If you want to delete if right after refresh you should do the refresh not in the background (using first parameter -> Refresh False) so that you have proper sequence of actions
Try setting the QueryTable.MaintainConnection property to False...
"Set MaintainConnection to True if the connection to the specified data source is to be maintained after the refresh and until the workbook is closed. The default value is True! And there doesn't seem to be a UI check box for this (Read/write Boolean)"
Still relevant years later...battling the same issue and this is the most helpful thread out there. My situation is a variant of the above and I will add my solution when I find it.
I am using an Access database for my data source and establish a querytable on a new sheet. I then add two more new sheets and try to establish a querytable using the same connection on each of them, but to a different Access table. The first querytable works just fine and I use .QueryTables(1).Delete and setting the querytable object to Nothing to make it disconnected.
However, the next sheet fails on establishing a new querytable using the same connection, which was not closed. I suspect (and will add the solution below) that I need to drop the connection before deleting the querytable. Rasmus' code above looks like the likely solution.