I am relatively new to using visual basic and I am having a problem populating a list box from a database. The error that comes up is Expression does not produce a value.
Here is the code from My form:
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Populate Blu Ray and DVD listboxes
Dim objMovies As New clsMovies
objMovies.Select_BR_List()
objMovies.Select_Dvd_List()
For Each strBluRay As String In objMovies.Select_BR_List
lstBluRay.Items.Add(strBluRay)
Next
For Each strDVD As String In objMovies.Select_Dvd_List
lstDvd.Items.Add(strDVD)
Next
End Sub
And here's the code from the class:
Public Sub Select_Dvd_List()
Dim objConnection As New SqlCeConnection(mstrCN)
'Create SQL statement
mstrSQL = "Select * from Dvd"
'Instantiate command
Dim objCommand As New SqlCeCommand(mstrSQL, objConnection)
'open Database
objCommand.Connection.Open()
'Instantiate Data Reader
Dim objDataReader As SqlCeDataReader
'Execute SQL
objDataReader = objCommand.ExecuteReader()
'read Sql results
Do While (objDataReader.Read)
mlstDvd.Add(objDataReader.Item("dvdTitle").ToString)
Loop
'Close
objCommand.Dispose()
objDataReader.Close()
objDataReader.Dispose()
objConnection.Close()
objConnection.Dispose()
End Sub
The issue is that you're trying to enumerate a Sub. In VB.NET, methods can either a Sub, which doesn't return a value, or a Function, which does return a value. Your Select_Dvd_List method is a Sub, so it doesn't return a value. You have this code though:
For Each strDVD As String In objMovies.Select_Dvd_List
That is trying to loop through the result of Select_Dvd_List but, as we've already established, Select_Dvd_List has no result. In that method, you are adding items to mlstDvd so surely that loop should be:
For Each strDVD As String In objMovies.mlstDvd
Related
I have a datagridview bound to a table that seems to work fine, but will not save changes to the database. I am using the same code as I used in another project, which did save changes, so I am flummoxed. Also, I have debugged and the save code is being called, just not working. The code in the form calls a separate class with business logic.
Code in the form below:
Private Sub frmAdminAssign_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Below is generated by Visual Studio when I select my data source for my datagridview
Credit_adminTableAdapter.Fill(DataSet1.credit_admin) ' Foreign key relationship to table being updated (lookup table).
LoanTableAdapter.Fill(DataSet1.loan) ' Table being updated
admin_assign = New AdminAssign()
admin_assign.FilterUnassigned(dgvAssign, LoanTableAdapter)
End Sub
Private Sub dgvAssign_CellEndEdit(sender As Object, e As DataGridViewCellEventArgs) Handles dgvAssign.CellEndEdit
admin_assign.SaveAssignmentChanges(DataSet1, LoanTableAdapter)
End Sub
Below is code in business logic class called from above:
Public Sub SaveAssignmentChanges(ByRef data_set As DataSet1, ByRef loan_table_adapter As DataSet1TableAdapters.loanTableAdapter)
' Saves changes to DB.
Dim cmdBuilder As SqlCommandBuilder
cmdBuilder = New SqlCommandBuilder(loan_table_adapter.Adapter)
loan_table_adapter.Adapter.UpdateCommand = cmdBuilder.GetUpdateCommand(True)
Try
loan_table_adapter.Adapter.Update(data_set)
Catch unknown_ex As Exception
Dim error_title As String = "Database Save Error"
Dim unknown_error As String = $"There was an error saving to the database.{vbNewLine}Error: {unknown_ex.ToString}"
MessageBox.Show(unknown_error, error_title, MessageBoxButtons.OK, MessageBoxIcon.Warning)
End Try
End Sub
The data from the datagridview is not saving to the tableadapter, which I found out by adding the lines below in the start of the second procedure:
Dim x As String = loan_table_adapter.GetData()(0)("note_number") ' Unchanged, check was right row
Dim y As String = loan_table_adapter.GetData()(0)("credit_admin_id") ' Changed in datagridview but still null (get null error)
I figured it out, it was related to a filter routine that is not above where I passed a tableadapter byref when I should have passed a datatable byval. So, related to one of jmcilhinney's byref vs byval comments above. See problem code below:
Public Sub FilterUnassigned(ByRef dgv_assigned As DataGridView, loan_table_adapter As DataSet1TableAdapters.loanTableAdapter)
' Should have passed in DataSet1.loan DataTable ByVal and used it below:
Dim unassigned_loans As DataView = loan_table_adapter.GetData().DefaultView()
unassigned_loans.RowFilter = "request_date Is Not Null AND numerated_assigned_user Is Null"
dgv_assigned.DataSource = unassigned_loans
End Sub
Also, skipping the SQLCommandBuilder commands and my code still works. So, all I need is one line as per jmcilhinney instead of 4 (excl error handling) as per below:
Try
loan_table_adapter.Update(data_set)
Catch unknown_ex As Exception
Dim error_title As String = "Database Save Error"
Dim unknown_error As String = $"There was an error saving to the database. Please contact Kevin Strickler to resolve.{vbNewLine}Error: {unknown_ex.ToString}"
MessageBox.Show(unknown_error, error_title, MessageBoxButtons.OK, MessageBoxIcon.Warning)
End Try
I have the following code which SELECTs data from a database and outputs a value to a label on the form:
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim strConn As String = System.Configuration.ConfigurationManager.ConnectionStrings("yourConnectionString").ToString()
Dim sql As String = "SELECT aid FROM tbl_RAPA WHERE username=#username"
Dim conn As New Data.SqlClient.SqlConnection(strConn)
Dim objDR As Data.SqlClient.SqlDataReader
Dim Cmd As New Data.SqlClient.SqlCommand(sql, conn)
Cmd.Parameters.AddWithValue("#username", User.Identity.Name)
conn.Open()
objDR = Cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection)
While objDR.Read()
Label1.Text = objDR("aid")
End While
End Sub
However, if the value in the database is empty, the program runs into an error. Is there a way for me to do this so the program just returns an empty value rather than crashing?
The error message i am given is System.InvalidCastException: 'Unable to cast object of type 'System.DBNull' to type 'System.Windows.Forms.Label'.' on the line Label1.Text = objDR("aid")
Database objects generally need to be closed and disposed. Using...End Using blocks will do this for you even if there is an error.
Since you are only expecting one piece of data you can use .ExecuteScalar which provides the first column of the first row of the result set. This method returns an object.
Try to always use the the .Add method with Parameters. See http://www.dbdelta.com/addwithvalue-is-evil/
and
https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/
and another one:
https://dba.stackexchange.com/questions/195937/addwithvalue-performance-and-plan-cache-implications
Here is another
https://andrevdm.blogspot.com/2010/12/parameterised-queriesdont-use.html
I had to guess at the database type so, check your database for the real value.
Don't update the User Interface until after the connection is closed and diposed. (End Using). I declared aid before the Using block so, it could be used after the block. Check if the object, aid, is not Nothing before adding it to the label's Text.
Imports MySql.Data.MySqlClient
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim aid As Object
Using conn As New MySqlConnection(ConfigurationManager.ConnectionStrings("yourConnectionString").ToString),
cmd As New MySqlCommand("SELECT aid FROM tbl_RAPA WHERE username=#username", conn)
cmd.Parameters.Add("#username", MySqlDbType.VarChar).Value = User.Identity.Name
aid = cmd.ExecuteScalar
conn.Open()
End Using
If Not IsNothing(aid) Then
Label1.Text = aid.ToString
End If
End Sub
I would add this before While objDR.Read() as a precaution in case your query returns no rows:
if objDR.HasRows
...
Then, to handle the null values (this is probably what you mean by empty):
If Not String.IsNullOrEmpty(objDR.Item("aid")) Then
Label1.Text = objDR("aid")
Else
Label1.Text = "Null !"
End if
You could also use ExecuteScalar() if you are only expecting one record. But you would need to handle the situation where no matching record is found.
I have this sub that generates an csv file from the result of a query
Private Sub generaReport(classe As String)
Dim query As String = "select bla bla bla"
Dim dt As New System.Data.DataTable()
Using con As New SqlConnection(My.Settings.dbstartConnectionString)
Using cmd As New SqlCommand(query, con)
cmd.Parameters.AddWithValue("#ieri", dataDa)
cmd.Parameters.AddWithValue("#domani", dataA)
cmd.Parameters.AddWithValue("#classe", classe)
Using sda As New SqlDataAdapter(cmd)
sda.Fill(dt)
End Using
End Using
End Using
Dim elencoCsv As String = ToCSV(dt)
If classe = "D" Then
File.Delete(nomeFileCsvD)
Using writer As New StreamWriter(nomeFileCsvD, True)
writer.WriteLine(elencoCsv)
End Using
Else
File.Delete(nomeFileCsvV)
Using writer As New StreamWriter(nomeFileCsvV, True)
writer.WriteLine(elencoCsv)
End Using
End If
InvioEmail(My.Settings.emails)
End
End Sub
I would call it two times like
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
generaReport("D")
generareport("V")
End Sub
but the second time it runs it still use "D" as parameter. How can I solve this? Thanks
As written, you have an End statement right before the End Sub line at the bottom of generaReport(). From the documentation, the End statement...
Terminates execution immediately.
So after executing with the "D" parameter, the entire application closes. It doesn't run "D" twice, it simply never runs "V".
Get rid of the End statement...
I'm trying to use the dataset for a report, but the data is gone when I try to use it. Here is my code for the most part:
Variables:
Dim ResultsDataView As DataView
Dim ResultsDataSet As New DataSet
Dim ResultsTable As New DataTable
Dim SQLQuery As String
Search:
This is where a datagrid is populated in the main view. The data shows up perfectly.
Private Sub Search(Optional ByVal Bind As Boolean = True, Optional ByVal SearchType As String = "", Optional ByVal SearchButton As String = "")
Dim SQLQuery As String
Dim ResultsDataSet
Dim LabelText As String
Dim MultiBudgetCenter As Integer = 0
SQLQuery = "A long and detailed SQL query that grabs N rows with 7 columns"
ResultsDataSet = RunQuery(SQLQuery)
ResultsTable = ResultsDataSet.Tables(0)
For Each row As DataRow In ResultsTable.Rows
For Each item In row.ItemArray
sb.Append(item.ToString + ","c)
Response.Write(item.ToString + "\n")
Response.Write(vbNewLine)
Next
sb.Append(vbCr & vbLf)
Next
'Response.End()
If Bind Then
BindData(ResultsDataSet)
End If
End Sub
Binding Data:
I think this is a cause in the issue.
Private Sub BindData(ByVal InputDataSet As DataSet)
ResultsDataView = InputDataSet.Tables("Results").DefaultView
ResultsDataView.Sort = ViewState("SortExpression").ToString()
ResultsGridView.DataSource = ResultsDataView
ResultsGridView.DataBind()
End Sub
Reporting action:
This is where I am trying to use the table data. But it is showing as nothing.
Protected Sub ReportButton_Click(sender As Object, e As EventArgs) Handles ReportButton.Click
For Each row As DataRow In ResultsTable.Rows
For Each item In row.ItemArray
Response.Write(item.ToString)
Next
Next
End Sub
The reason I'm trying to loop through this data is to both display the data in a gridview on the main view as well as export the data to CSV. If there is a different way to export a SQL query to CSV, I'm open to any suggestions.
There has to be something I can do to get the data from the SQL query to persist through the ReportButton_Click method. I've tried copying the datatable, I've tried global variables, I've tried different methods of looping through the dataset. What am I missing?!
Thank you all in advance.
EDIT
Here is the Page_Load:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Page.IsPostBack Then
'set focus to postback control
Dim x As String = GetPostBackControlName(Page)
If Len(x) > 0 Then
x = x.Replace("$", "_")
SetFocus(x)
End If
End If
If Not IsPostBack Then
ResultsGridView.AllowPaging = False
'Enable Gridview sorting
ResultsGridView.AllowSorting = True
'Initialize the sorting expression
ViewState("SortExpression") = "ID DESC"
'Populate the Gridview
Search()
End If
End Sub
In your search function add this line after the ResultsTable setting
ResultsTable = ResultsDataSet.Tables(0)
Session("LastSearch") = ResultsTable
Then in your report click event handler recover your data from the Session variable
Protected Sub ReportButton_Click(sender As Object, e As EventArgs) Handles ReportButton.Click
ResultsTable = DirectCast(Session("LastSearch"), DataTable)
For Each row As DataRow In ResultsTable.Rows
For Each item In row.ItemArray
Response.Write(item.ToString)
Next
Next
End Sub
You need to read about ASP.NET Life Cycle and understand that every time ASP.NET calls your methods it creates a new instance of your Page class. Of course this means that global page variables in ASP.NET are not very useful.
Also consider to read about that Session object and not misuse it.
What is the difference between SessionState and ViewState?
I am trying to use a VB generated textbox to display the values/names, that are within an SQL database. I started with VB and SQL last week; I tried to use a self-built method named GetUserInfo() to display the values, but it doesnt display anything.
This is the segment used for the Textbox in VB
Public Class user_selection_screen
Private SQL As SQLControl
Private Authuser As String
Private Sub ListBox1_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles box_user_selection.SelectedIndexChanged
GetUserInfo()
End Sub
Public Sub GetUserInfo()
SQL.RunQuery("SELECT Name" & "FROM" ""User"")
For Each i As Object In SQL.SQLDS.Tables(0).Rows
box_user_selection.Text = i.Item("Name" & vbCrLf)
Next
End Sub
I started learning VB and SQL last week, so please keep the explanations as simple as possible.
When you run SQL.RunQuery("SELECT Name" & "FROM" ""User"")
are you sure it fills the DS SQL.SQLDS.Tables(0).Rows?
If yes then,
Dim StrVal As String
For i = 0 To SQL.SQLDS.Tables(0).Rows.Count - 1
StrVal = StrVal & SQL.SQLDS.Tables(0).Rows(i).Item("Name").ToString()
Next i
box_user_selection.Text = StrVal
To see if your SQLDS.Table really returns a row, Msgbox(SQL.SQLDS.Tables(0).Rows.Count)
Make sure your SQLDS Has value.
If your SQLDS is Dataset, Loop through your SQLDS table by datarow. see example
For Each dr As DataRow In SqlDs.Tables(0).Rows
box_user_selection.Text = Convert.ToString(dr("Name"))
Next