Query in VB.net sometimes doesn't work - sql

I have a functionality which saves the information from a webform to the database, which is working fine.
This is my code for save functionality in Onspec.aspx.vb page
Public Sub SaveClick(ByVal sender As Object, ByVal e As System.EventArgs)
If Not Page.IsValid Then
litMessage.Text = ""
Exit Sub
End If
Try
Dim sName As String = ""
With EmployerCandidate
.employerid = Master.Employer.ID
.employeruserid = 0
Try
.CVID = DocId
Catch
End Try
.Name = uxName.Text
.SurName = uxSurname.Text
Try
.PostCode = uxPostcode.Text
Catch ex As Exception
End Try
.Email = uxEmail.Text
Try
.MobileNo = uxMobileNo.Text
Catch ex As Exception
End Try
.OnSpec = True
.OnSpecType = uxOnSpecCategory.SelectedItem.Text
.Source = uxSourceID.SelectedItem.Text
.LastEmployer = uxEmployer.Text
.LastJobTitle = uxJobtitle.Text
.Profile = uxProfile.Text.Trim
End With
' email()
ResetForm()
panForm.Visible = False
panUpload.Visible = True
uxSubmit.Visible = False
uxUpload.Visible = True
litMessage.Text = "Thank you for submitting your details! We'll be in touch when appropriate vacancy arises. <a href='#' onclick='parent.$.colorbox.close()'>Close</a>"
UploadPanel.Visible = False
Response.Redirect("onspec-complete.aspx?e=" & Master.Employer.ID)
Catch ex As Exception
litMessage.Text = Core.Helper.FancyMessage("Error as occurred - " & ex.Message.ToString, "ERROR")
End Try
End Sub
Now, I want to send emails along with saving the data in the database so I added the following lines of code before ResetForm().
Dim specmatch As DataRow = DB.GetRow("SELECT TOP 1 name,email,password FROM [user] usr JOIN employeruser empUsr ON usr.id = empUsr.userid WHERE empUsr.empusertype = 1 AND empUsr.employerid = #eid ", DB.SIP("eid", LocalHelper.UserEmployerID))
If my query returns a value then I want to send email by calling the email function.
If specmatch IsNot Nothing Then
email()
End If
But in this line of code the employerid value is sometimes empty. It can't pick the id therefore it is returning an empty row. And therefore it's not calling the email function.
This id is the same as
.employerid = Master.Employer.ID
But if I replace the LocalHelper.UserEmployerID with Master.Employer.ID the form gives an error:
Object reference not set to an instance of an object.
employerid is an integer value.
I have also tried to add the following lines of code in this page(Onspec.aspx.vb)
Public ReadOnly Property EmployerId() As Integer
Get
Return Master.Employer.ID
End Get
End Property
But I get the same error:
Object reference not set to an instance of an object.
The above lines of code does not make any difference.
So I replaced Master.Employer.ID with LocalHelper.UserEmployerID
Where in localhelper.vb file (under appcode folder) it is determining employerid from the website with following lines of code.
Public Shared Function UserEmployerID() As Integer
If HttpContext.Current.Items("lh_useremployerid") Is Nothing Then
If LocalHelper.UserTypeCode = "e" Then
HttpContext.Current.Items("lh_useremployerid") = Core.DB.GetInteger("SELECT employerid FROM employeruser WHERE userid = " & LocalHelper.UserID)
Else
HttpContext.Current.Items("lh_useremployerid") = 0
End If
End If
Return HttpContext.Current.Items("lh_useremployerid")
End Function
These lines of code has been used in many places and works perfectly fine. In this case as well, it was working fine last Friday and now it's not. There was no changes made.
This is my email function
Private Sub email()
Dim strCandidateName As String = uxName.Text.Trim & " " & uxSurname.Text.Trim
Dim strCandidateSurname As String = uxSurname.Text
Dim strCandidateEmail As String = uxEmail.Text.Trim
Dim strCandidatePhone As String = uxMobileNo.Text.Trim
Dim strCPass As String = "mpb123"
Dim strContactType As String = "Speculative Application has been submited on the category of " & uxOnSpecCategory.SelectedItem.Text
Dim strContactMessage As String = uxProfile.Text.Trim
'''''''''''''''''''variable
Dim qq As String = String.Format("Select top 1 name, email, password FROM [user] WHERE id in (Select userid FROM employeruser WHERE empusertype=1 and employerid= " & LocalHelper.UserEmployerID & ")")
Dim drow As DataRow = Core.DB.GetRow(qq)
Dim semail As String = drow.Item("email").ToString
Dim sname As String = drow.Item("name").ToString
Dim spass As String = drow.Item("password").ToString
'''''''''''''''''''variable
Dim Email As Core.Email
'New Onspec Candidate Email sent to EmployerUser who is assigned to receive onspec email
Email = New Core.Email
With Email
.ContentID = 99
.Replacement("ContactName", strCandidateName)
.Replacement("ContactEmail", strCandidateEmail)
.Replacement("ContactTelephone", strCandidatePhone)
.Replacement("ContactType", strContactType)
.Replacement("ContactMessage", strContactMessage)
.Replacement("AdminContactName", sname)
.Replacement("AdminContactEmail", semail)
.Replacement("SiteName", LocalHelper.AppSetting("sitename"))
Dim attachments As New Generic.List(Of String)
If EmployerCandidate.CVID > 0 Then
Dim doc As New Document(EmployerCandidate.CVID)
attachments.Add(doc.PathOnDisc)
End If
.Attachments = Join(attachments.ToArray(), ";")
.Send()
End With
End Sub
GetRow function is defined in my database.vb page like following which is also used in many other places.
Shared Function GetRow(ByVal selectQueryText As String, ByVal ParamArray params As SqlParameter()) As DataRow
Return GetRowFromDB(selectQueryText, CommandType.Text, params)
End Function
And
Shared Function GetRowFromDB(ByVal selectCommandText As String, ByVal selectCommandType As CommandType, ByVal ParamArray params As SqlParameter()) As DataRow
Dim conn As SqlConnection = Nothing
Try
conn = GetOpenSqlConnection()
Return GetRowFromDB(conn, selectCommandText, selectCommandType, params)
Finally
If conn IsNot Nothing Then conn.Dispose()
End Try
End Function
Please suggest ways on how I can organize my code so that it works all the time.

Related

Procedure or function 'p_xxx ' has too many arguments specified

I get the error at this line: sqlDataAdapDelProtocol.Fill(dsDelProtocol, "dsProtocols"), I dint understand why. The error states : Procedure or function p_GetLinkedProcuduresProtocol has too many arguments specified
Protected Sub btnDeletePTC_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim sqlString As String = String.Empty
Dim PTC_ID As Integer
sqlString = "p_GetLinkedProcuduresProtocol"
Dim sqlConnDelProtocol As New SqlClient.SqlConnection(typicalConnectionString("MyConn").ConnectionString)
sqlConnDelProtocol.Open()
Dim sqlDataAdapDelProtocol As New SqlClient.SqlDataAdapter(sqlString, sqlConnDelProtocol)
sqlDataAdapDelProtocol.SelectCommand.CommandType = CommandType.StoredProcedure
Dim sqlParProtocolName As New SqlClient.SqlParameter("#PTC_ID", SqlDbType.Int, 255)
sqlDataAdapDelProtocol.SelectCommand.Parameters.Add(sqlParProtocolName)
Dim dsDelProtocol As New DataSet
Dim MessageAud = "Are you sure you want to delete this question, the question is linked to:"
Dim MessageNoAud = "Are you sure you want to delete this question"
sqlDataAdapDelProtocol.SelectCommand.Parameters.AddWithValue("PTC_ID", PTC_ID)
sqlDataAdapDelProtocol.Fill(dsDelProtocol, "dsProtocols")
If dsDelProtocol.Tables("dsProtocols").Rows.Count > 0 Then
lblMessageSure.Text = (CType(MessageAud, String))
For Each dr As DataRow In dsDelProtocol.Tables(0).Rows
lblAudits = (dr("dsProtocols"))
Next
Else
lblMessageSure.Text = (CType(MessageNoAud, String))
End If
Dim success As Boolean = False
Dim btnDelete As Button = TryCast(sender, Button)
Dim row As GridViewRow = DirectCast(btnDelete.NamingContainer, GridViewRow)
Dim cmdDelete As New SqlCommand("p_deleteProtocolStructure")
cmdDelete.CommandType = CommandType.StoredProcedure
cmdDelete.Parameters.AddWithValue("PTC_ID", PTC_ID)
Call DeleteProtocol(PTC_ID)
conn = NewSqlConnection(connString, EMP_ID)
cmdDelete.Connection = conn
If Not conn Is Nothing Then
If conn.State = ConnectionState.Open Then
Try
success = cmdDelete.ExecuteNonQuery()
Call UpdateProtocolNumbering(PTS_ID)
txtAddPTCNumber.Text = GetNextNumber(PTS_ID)
Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "TreeView", _
"<script language='javascript'>" & _
" parent.TreeView.location='TreeView.aspx?MainScreenURL=Protocols.aspx&PTS_ID=" & PTS_ID & "';" & _
"</script>")
conn.Close()
Catch ex As Exception
success = False
conn.Close()
Throw ex
End Try
End If
End If
If success = True Then
Call GenerateQuestionsGrid()
Call Message(Me, "pnlMessage", "Question successfully deleted.", Drawing.Color.Green)
Else
Call Message(Me, "pnlMessage", "Failed to delete Question.", Drawing.Color.Red)
End If
End Sub
You are adding the same parameter twice, once without a value, then with a value. Instead of adding it another time, set the value on the parameter that you already have.
Replace this:
sqlDataAdapDelProtocol.SelectCommand.Parameters.AddWithValue("PTC_ID", PTC_ID)
with this:
sqlParProtocolName.Vaue = PTC_ID
Side note: Always start parameter names for Sql Server with #. The parameter constructor will add it if it's not there so it will work without it, but this is an undocumented feature, so that could change in future versions.

VB.Net Global DataSets inside a public function

I am having some problem with a function that I hope you can help.
My Application is a simple one, it uses an Access database to load employee information and creates letters and financial breakdown sheet from word templates that users can then print and save back to the database.
I started by creating a dataset containing several datatables for each form subroutine but it resulted in literally hundreds of lines of repeated code. But it worked.
What I want to do, is have one dataset containing all the information needed about an employee and be able to reference it over several forms at the same time. So i created a public module that looks like this:
Public Module Datasets
Public update As String
Dim pCn As OleDb.OleDbConnection
Public Function CSofwareDataSet() As DataSet
'open new connection to database
pCn = New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=G:\CGI Project\CorrespondenceSoftware\Database1.accdb; Persist Security Info=False;")
Try
Call pCn.Open() 'opens the connection
Catch ex As Exception
MessageBox.Show("Could not open a database connection! 1")
MessageBox.Show(ex.ToString)
End Try
CSofwareDataSet = New DataSet
Dim daOPG As New OleDb.OleDbDataAdapter("SELECT * FROM Overpayment WHERE PayNumber='" & Main.tbPayNumber.Text & "' AND Gross=1", pCn) 'get all data from Overpayment Details table
Dim daOPN As New OleDb.OleDbDataAdapter("SELECT * FROM Overpayment WHERE PayNumber='" & Main.tbPayNumber.Text & "' AND Net=1", pCn) 'get all data from Overpayment Details table
Dim daOPR As New OleDb.OleDbDataAdapter("SELECT * FROM OvpReasons", pCn) 'get overpayment reasons
Dim daREC As New OleDb.OleDbDataAdapter("SELECT * FROM TaxYear", pCn) 'get recovery date options
Dim daEMP As New OleDb.OleDbDataAdapter("SELECT * FROM EmployeeDetails WHERE PayNumber='" & Main.tbPayNumber.Text & "' AND Active=1 ", pCn) 'get all data from Employee Details table
Dim daCON As New OleDb.OleDbDataAdapter("SELECT * FROM Consultant", pCn) 'get all data from Consultant Details table
Dim daSET As New OleDb.OleDbDataAdapter("SELECT * FROM Settings", pCn) 'get all data from Consultant Details table
'Find the primary key (if missing)
daOPG.MissingSchemaAction = MissingSchemaAction.AddWithKey
daOPN.MissingSchemaAction = MissingSchemaAction.AddWithKey
daOPR.MissingSchemaAction = MissingSchemaAction.AddWithKey
daREC.MissingSchemaAction = MissingSchemaAction.AddWithKey
daEMP.MissingSchemaAction = MissingSchemaAction.AddWithKey
daCON.MissingSchemaAction = MissingSchemaAction.AddWithKey
daSET.MissingSchemaAction = MissingSchemaAction.AddWithKey
'setup prefixes
Dim cbOPG As New OleDb.OleDbCommandBuilder(daOPG)
cbOPG.QuotePrefix = "["
cbOPG.QuoteSuffix = "]"
Dim cbOPN As New OleDb.OleDbCommandBuilder(daOPN)
cbOPG.QuotePrefix = "["
cbOPG.QuoteSuffix = "]"
Dim cbOPR As New OleDb.OleDbCommandBuilder(daOPR)
cbOPG.QuotePrefix = "["
cbOPG.QuoteSuffix = "]"
Dim cbREC As New OleDb.OleDbCommandBuilder(daREC)
cbOPG.QuotePrefix = "["
cbOPG.QuoteSuffix = "]"
Dim cbEMP As New OleDb.OleDbCommandBuilder(daEMP)
cbEMP.QuotePrefix = "["
cbEMP.QuoteSuffix = "]"
Dim cbCON As New OleDb.OleDbCommandBuilder(daCON)
cbEMP.QuotePrefix = "["
cbEMP.QuoteSuffix = "]"
Dim cbSET As New OleDb.OleDbCommandBuilder(daSET)
cbEMP.QuotePrefix = "["
cbEMP.QuoteSuffix = "]"
If CSofwareDataSet.HasChanges Then
Try
daEMP.Update(CSofwareDataSet, "EmployeeDetails")
daOPG.Update(CSofwareDataSet, "OverPaymentGross")
daOPN.Update(CSofwareDataSet, "OverPaymentNet")
daSET.Update(CSofwareDataSet, "Settings")
MessageBox.Show("Success! Records updated.")
update = "0"
Catch ex As Exception
MessageBox.Show("Oops - something went wrong and it didn't update")
update = "0"
End Try
ElseIf CSofwareDataSet.Tables.Count = 0 Then
daOPG.Fill(CSofwareDataSet, "OverPaymentGross")
daOPN.Fill(CSofwareDataSet, "OverPaymentNet")
daOPR.Fill(CSofwareDataSet, "OverPaymentReasons")
daREC.Fill(CSofwareDataSet, "RecoveryDates")
daEMP.Fill(CSofwareDataSet, "EmployeeDetails")
daCON.Fill(CSofwareDataSet, "ConsultantDetails")
daSET.Fill(CSofwareDataSet, "Settings")
End If
'If update = "1" Then
' Try
' daEMP.Update(CSofwareDataSet, "EmployeeDetails")
' daOPG.Update(CSofwareDataSet, "OverPaymentGross")
' daOPN.Update(CSofwareDataSet, "OverPaymentNet")
' daSET.Update(CSofwareDataSet, "Settings")
'
' MessageBox.Show("Success! Records updated.")
' update = "0"
' Catch ex As Exception
' MessageBox.Show("Oops - something went wrong and it didn't update")
' update = "0"
' End Try
' End If
pCn.Close()
End Function
End Module
On each form, it gets referenced like this (as an example):
Imports WeifenLuo.WinFormsUI.Docking
Imports Word = Microsoft.Office.Interop.Word
Imports CorrespondenceSoftware.Datasets
Public Class GrossInput
Dim loading = "1"
Dim NewEmployee = "0" 'sets the default new employee flag to 0
Private pCn As OleDb.OleDbConnection
Private Sub GrossInput_Load(ByVal Sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Try
Try
If CSofwareDataSet.Tables("EmployeeDetails").Rows.Count > 0 Then
For i As Integer = 0 To CSofwareDataSet.Tables("EmployeeDetails").Rows.Count - 1
cbTitle.Text = CSofwareDataSet.Tables("EmployeeDetails").Rows(i)(2)
tbFName.Text = CSofwareDataSet.Tables("EmployeeDetails").Rows(i)(3)
tbLName.Text = CSofwareDataSet.Tables("EmployeeDetails").Rows(i)(4)
tbAddress1.Text = CSofwareDataSet.Tables("EmployeeDetails").Rows(i)(5)
tbAddress2.Text = CSofwareDataSet.Tables("EmployeeDetails").Rows(i)(6)
tbAddress3.Text = CSofwareDataSet.Tables("EmployeeDetails").Rows(i)(7)
tbAddress4.Text = CSofwareDataSet.Tables("EmployeeDetails").Rows(i)(8)
tbPostcode.Text = CSofwareDataSet.Tables("EmployeeDetails").Rows(i)(9)
tbWorkLocation.Text = CSofwareDataSet.Tables("EmployeeDetails").Rows(i)(10)
tbWorkLocation.Enabled = False
tbPostcode.Enabled = False
tbAddress4.Enabled = False
tbAddress3.Enabled = False
tbAddress2.Enabled = False
tbAddress1.Enabled = False
tbLName.Enabled = False
tbFName.Enabled = False
cbTitle.Enabled = False
chkMSC.Enabled = False
chkOfficer.Enabled = False
chkStaff.Enabled = False
bnSaveEmp.Enabled = False
bnEditEmp.Enabled = True
Next
End If
If CSofwareDataSet.Tables("EmployeeDetails").Rows(0)(11) = "1" Then
chkOfficer.Checked = True
Else
chkOfficer.Checked = False
End If
If CSofwareDataSet.Tables("EmployeeDetails").Rows(0)(12) = "1" Then
chkStaff.Checked = True
Else
chkStaff.Checked = False
End If
If CSofwareDataSet.Tables("EmployeeDetails").Rows(0)(13) = "1" Then
chkMSC.Checked = True
Else
chkMSC.Checked = False
End If
Catch ex As Exception
MessageBox.Show(ex.ToString)
MessageBox.Show("Employee not found. Ensure pay number is correct and create a new record")
NewEmployee = "1" ' tells the program to create a new record if saved
cbReference.Enabled = False
cbReference.Text = ""
bnEditEmp.Enabled = False
End Try
'display the overpayment references to the user
If CSofwareDataSet.Tables("OverPaymentGross").Rows.Count > 0 Then
For i As Integer = 0 To CSofwareDataSet.Tables("OverPaymentGross").Rows.Count - 1
cbReference.Items.Add(CSofwareDataSet.Tables("OverPaymentGross").Rows(i)(2))
Next
End If
'display the available consultants to the user
If CSofwareDataSet.Tables("ConsultantDetails").Rows.Count > 0 Then
For i As Integer = 0 To CSofwareDataSet.Tables("ConsultantDetails").Rows.Count - 1
cbConsultant.Items.Add(CSofwareDataSet.Tables("ConsultantDetails").Rows(i)(1) & " " & CSofwareDataSet.Tables("ConsultantDetails").Rows(i)(2))
Next
End If
'display the available Overpayment reasons to the user
If CSofwareDataSet.Tables("OverPaymentReasons").Rows.Count > 0 Then
For i As Integer = 0 To CSofwareDataSet.Tables("OverPaymentReasons").Rows.Count - 1
cbReason.Items.Add(CSofwareDataSet.Tables("OverPaymentReasons").Rows(i)(1))
Next
End If
'Load other recovery date options
If CSofwareDataSet.Tables("RecoveryDates").Rows.Count > 0 Then
For i As Integer = 0 To CSofwareDataSet.Tables("RecoveryDates").Rows.Count - 1
cbStartRecovery.Items.Add(CSofwareDataSet.Tables("RecoveryDates").Rows(i)(1))
Next
End If
Catch ex As Exception
MessageBox.Show(ex.ToString) 'Show any errors to the user
End Try
loading = "0"
End Sub
Now! the problem that I'm having is that, this does work and run without any errors BUT every time the CSSoftwareDataSet function runs it populates the tables correctly and returns the expected results but it then deletes the datatable data so every time the function is referenced from a winform it needs to haul all the data from the access database from scratch, severely impacting on the performance of the program. The tables wont update properly because its not storing the datatable information and as soon as its inserted its forgotten but again, produces no errors. An example of my update script looks like this:
Else 'create a new record
'create a new reference
Dim REFRowCount = CSofwareDataSet.Tables("OverPaymentGross").Rows.Count + 1 'count the number of rows in table and add 1
Dim NewREF = "OVPG" & Main.tbPayNumber.Text & "-" & REFRowCount
'Find todays date and reply dates
Dim TodayDatedate = Format(Now.Date(), "dd/MM/yyyy")
Dim ReplyDatedate = Format(Now.Date.AddDays(21), "dd/MM/yyyy")
'Create a new row
Dim OPNew As DataRow = CSofwareDataSet.Tables("OverPaymentGross").NewRow() 'create a variable to contain the new row
OPNew.Item(1) = Main.tbPayNumber.Text
OPNew.Item(2) = NewREF
OPNew.Item(3) = tbOverpaymentAmount.Text.ToString
OPNew.Item(4) = tbMonRec.Text
OPNew.Item(5) = tbTaxP.Text
OPNew.Item(6) = TodayDatedate
OPNew.Item(7) = ReplyDatedate
OPNew.Item(8) = tbMoRep.Text
OPNew.Item(9) = cbStartRecovery.Text
OPNew.Item(10) = "1" 'Set as gross
OPNew.Item(11) = "0" 'do not set as net
OPNew.Item(12) = cbReason.Text
OPNew.Item(13) = tbAI.Text
OPNew.Item(14) = dtpStart.Value.Date
OPNew.Item(15) = dtpFinish.Value.Date
OPNew.Item(16) = cbConsultant.Text
OPNew.Item(17) = tbPosition.Text
Call CSofwareDataSet.Tables("OverPaymentGross").Rows.Add(OPNew) 'fill the new row and insert the data
There must be a solution to this. To create a dataset that holds its data in session while you open other winforms until it is reset. I'm out of ideas because i really don't want to go back to repeating all this code for practically every subroutine in my program.
I hope I've explained it OK .. Any help here will be greatly appreciated.
Many thanks,
Shane
You can declare the DataSet globally, populate it in a function (sub), which is called just at the start, and retrieve the information by accessing the variable rather than by calling the function over and over. Your code uses a somehow ambiguous approach (same name for function and for variable) which, together with the VB rules (functions might not include a Return statement but a variable with the function's name) does not play to your favor.
Sample code converting the DataSet into a public variable and renaming the function (and converting it into a sub: what is the point of a function now?):
Public CSofwareDataSet As DataSet
Public Sub populateDS()
'open new connection to database
pCn = New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=G:\CGI Project\CorrespondenceSoftware\Database1.accdb; Persist Security Info=False;")
Try
Call pCn.Open() 'opens the connection
Catch ex As Exception
MessageBox.Show("Could not open a database connection! 1")
MessageBox.Show(ex.ToString)
End Try
CSofwareDataSet = New DataSet
'Remaining code
End Sub
Call this sub just once (right at the start of your application; or every time new data has to be retrieved from the DB) and continue using CSofwareDataSet as so far (although as a variable, by removing the Call bits; which, on the other hand, are not required in VB.NET at all).

How to Group and Sort details by date-bubble sort?

First off thanks for reading this, I've spent the last four hours trying to work this out.
Essentially I'm building a application in where the user inputs: date, Name, Phone number and instructor name to a simple csv .txt database file. I've got all that working.
Now all I need to do is somehow group the details together, and separate from other entries.
I now want to sort these grouped details by date through a bubble sort and then save it to another file. WHen I say sort, I want the other details to go along with the date.
The date when inputted to the application has to be: (yyMMddhhmm)
Eg: 1308290930 = 9:30 on 29/08/13
I can post what I've done thus far.
Public Class Form2
Dim currentRow As String()
Dim count As Integer
Dim one As Integer
Dim two As Integer
Dim three As Integer
Dim four As Integer
Dim catchit(100) As String
Dim count2 As Integer
Dim arrayone(50) As Integer
Dim arraytwo(50) As String
Dim arraythree(50) As Integer
Dim arrayfour(50) As String
Dim bigstring As String
Dim builder As Integer
Dim twodata As Integer
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Me.RichTextBox1.LoadFile("D:\completerecord.txt", RichTextBoxStreamType.PlainText)
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser("D:\completerecord.txt")
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
Dim count As Integer
count = 0
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
Dim currentField As String
For Each currentField In currentRow
' makes one array to contain a record for each peice of text in the file
'MsgBox(currentField) '- test of Field Data
' builds a big string with new line-breaks for each line in the file
bigstring = bigstring & currentField + Environment.NewLine
'build two arrays for the two columns of data
If (count Mod 2 = 1) Then
arraytwo(two) = currentField
two = two + 1
'MsgBox(currentField)
ElseIf (count Mod 2 = 0) Then
arrayone(one) = currentField
one = one + 1
End If
count = count + 1
'MsgBox(count)
Next
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Error Occured, Please contact Admin.")
End Try
End While
End Using
RichTextBox1.Text = bigstring
' MsgBox("test")
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim NoMoreSwaps As Boolean
Dim counter As Integer
Dim Temp As Integer
Dim Temp2 As String
Dim listcount As Integer
Dim builder As Integer
Dim bigString2 As String = ""
listcount = UBound(arraytwo)
'MsgBox(listcount)
builder = 0
'bigString2 = ""
counter = 0
Try
'this should sort the arrays using a Bubble Sort
Do Until NoMoreSwaps = True
NoMoreSwaps = True
For counter = 0 To (listcount - 1)
If arraytwo(counter) > arraytwo(counter + 1) Then
NoMoreSwaps = False
If arraytwo(counter + 1) > 0 Then
Temp = arraytwo(counter)
Temp2 = arrayone(counter)
arraytwo(counter) = arraytwo(counter + 1)
arrayone(counter) = arrayone(counter + 1)
arraytwo(counter + 1) = Temp
arrayone(counter + 1) = Temp2
End If
End If
Next
If listcount > -1 Then
listcount = listcount - 1
End If
Loop
'now we need to output arrays to the richtextbox first we will build a new string
'and we can save it to a new sorted file
Dim FILE_NAME As String = "D:\sorted.txt"
If System.IO.File.Exists(FILE_NAME) = True Then
Dim objWriter As New System.IO.StreamWriter(FILE_NAME, True)
While builder < listcount
bigString2 = bigString2 & arraytwo(builder) & "," & arrayone(builder) + Environment.NewLine
objWriter.Write(arraytwo(builder) & "," & arrayone(builder) + Environment.NewLine)
builder = builder + 1
End While
RichTextBox2.Text = bigString2
objWriter.Close()
MsgBox("Text written to log file")
Else
MsgBox("File Does Not Exist")
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
End Class
Create a class to hold the information for each entry, like this:
Public Class MyEntry
Public Property TheDate() As DateTime
Get
Return m_Date
End Get
Set
m_Date = Value
End Set
End Property
Private m_Date As DateTime
Public Property Name() As String
Get
Return m_Name
End Get
Set
m_Name = Value
End Set
End Property
Private m_Name As String
Public Property PhoneNumber() As String
Get
Return m_PhoneNumber
End Get
Set
m_PhoneNumber = Value
End Set
End Property
Private m_PhoneNumber As String
Public Property Instructor() As String
Get
Return m_Instructor
End Get
Set
m_Instructor = Value
End Set
End Property
Private m_Instructor As String
Public Sub New(date As DateTime, name As String, phoneNumber As String, instructor As String)
TheDate = date
Name = name
PhoneNumber = phoneNumber
Instructor = instructor
End Sub
End Class
Now you can create a list of the above class, like this:
Private entries As var = New List(Of MyEntry) From { _
New MyEntry(DateTime.Now.AddDays(-1), "Dummy 1", "555-123-4567", "Instructor A"), _
New MyEntry(DateTime.Now.AddDays(-1), "Dummy 2", "555-124-4567", "Instructor B"), _
New MyEntry(DateTime.Now.AddDays(-1), "Dummy 3", "555-125-4567", "Instructor C"), _
New MyEntry(DateTime.Now.AddDays(-2), "Dummy 4", "555-126-4567", "Instructor A"), _
New MyEntry(DateTime.Now.AddDays(-2), "Dummy 5", "555-127-4567", "Instructor B") _
}
Note: You will need to substitute your real values here and would use some type of looping structure to do that.
Now you can apply the LINQ GroupBy function to the list of entries, like this:
Private entriesByDate As var = entries.GroupBy(Function(x) x.TheDate).ToList()
This results in a list of two entries for the dummy data I created above, your amount of groupings will vary based upon your actual data.
Now you could loop through the list of groups, like this:
For Each entry In entriesByDate
' Put logic here to save each group to file
Next
My suggestion is to add a marker at the end of reach recoord (date, time, etc.). I use "|". Then, when you read the data back, split the records into an array, and read them out using that.
So it would be:
130829|0930|<name>|<phone number>|etc
Do you understand?

Recursive Function Not Returning

I am hopeing someone can help me here with a recursive function I have that is not returning either true or false as I would have espected it to. The function loops through a Active Directory group for its members and then calls itself if it encounters any groups within the membership in order to gets its members as well. I am trying to return either true or false based on if any errors were encountered but not haveing any luck at all. It appears to just hang and never return back to the primary calling sub that starts the recursive function. Below is my code I am using:
Private Sub StartAnalysis(ByVal grp As String, ByVal grpdn As String, ByVal reqid As String)
Dim searchedGroups As New Hashtable
'prior work before calling sub
searchedGroups.Add(grp, 1)
Dim iserror As Boolean = GetGroupMembers(grpdn, searchedGroups, reqid)
If iserror = False Then
'do stuff
Else
'do stuff
End If
'cleanup
End Sub
Public Function GetGroupMembers(ByVal groupSearch As String, ByVal searchedGroups As Hashtable, ByVal requestID As String) As Boolean
Dim iserror As Boolean = False
Try
Dim lastQuery As Boolean = False
Dim endLoop As Boolean = False
Dim rangeStep As Integer = 999
Dim rangeLow As Integer = 0
Dim rangeHigh As Integer = rangeLow + rangeStep
Do
Dim range As String = "member"
If lastQuery = False Then
range = String.Format("member;range={0}-{1}", rangeLow, rangeHigh)
Else
range = String.Format("member;range={0}-*", rangeLow)
endLoop = True
End If
Dim group As SearchResult = QueryObject(groupSearch, range)
Dim groupCN As String = group.Properties("cn")(0).ToString
If group.Properties.Contains(range) Then
For Each member As Object In group.Properties(range)
Dim user As SearchResult = QueryObject(member.ToString, "member")
Dim userCN = user.Properties("cn")(0).ToString
If Not user.Properties.Contains("member") Then
Dim userMail = String.Empty
If user.Properties.Contains("mail") Then
userMail = user.Properties("mail")(0).ToString
End If
userCN = userCN.Replace("'", "''")
Dim qry As String = _
"INSERT INTO group_analysis_details (request_id, member_name, member_email, member_group) " & _
"values ('" & requestID & "', '" & userCN & "', '" & userMail & "', '" & groupCN & "')"
Dim sqlConn As SqlConnection = New SqlConnection(cs)
Dim sqlCmd As SqlCommand = New SqlCommand(qry, sqlConn)
sqlConn.Open()
sqlCmd.ExecuteNonQuery()
sqlConn.Close()
sqlCmd.Dispose()
sqlConn.Dispose()
Else
If Not searchedGroups.ContainsKey(userCN) Then
searchedGroups.Add(userCN, 1)
iserror = GetGroupMembers(user.Properties("distinguishedname")(0).ToString, searchedGroups, requestID)
If iserror = True Then Return iserror
Else
searchedGroups(userCN) += 1
End If
End If
Next
Else
lastQuery = True
End If
If lastQuery = False Then
rangeLow = rangeHigh + 1
rangeHigh = rangeLow + rangeStep
End If
Loop While endLoop = False
Return iserror
Catch ex As Exception
myEvents.WriteEntry("Error while analyzing the following group: " & groupSearch & vbCrLf & vbCrLf & _
"Details of the error are as follows: " & ex.Message, EventLogEntryType.Error)
Return True
End Try
End Function
Hopefully someone can point out where I might be making my error is this.
Thanks,
Ron
Generally if you're using a 'Do...Loop While' and manually setting the exit condition inside the loop it's very easy to get stuck in an infinite loop which is what causes the program to hang.
It looks like you're not setting endloop = True in all circumstances. Try changing it to an Exit Do and adding one to each of the various conditions you have. A bit of trial and error will be required to get it just right.
Also to make your life easier extract the database insert code into a seperate function and call it when needed.

The select command property has not been initialized before calling 'Fill'

I am working on a Windows forms project that connects to a Microsoft Access database, reads the the file, does some math and then provides some basic statistics back. Right now I am teaching myself VB and I know the code below could be more efficient. However, right now I am just trying to make it functional.
The program filters the data it needs via sql, and there are several sql statements. I separated the code for each of the sql statements and into a subroutine so that I could call each one when the form loads and also when the user clicks a button to update. The program works fine on the form load, however, when you click the update button you get the following error on the 'odaCalls.Fill' in subroutine Count(): "The select command property has not been initialized before calling 'Fill'.
Any help is greatly appreciated. I have searched on google and tried the suggestions found there but have not found a fix.
Option Explicit On
Public Class Form1
'Count() Variables
Dim strSQL = "SELECT * FROM tblcallLog"
Dim strPath As String = "Provider=Microsoft.ACE.OLEDB.12.0 ;" _
& "Data Source=C:\callLogRev2_be.accdb"
Dim odaCalls As New OleDb.OleDbDataAdapter(strSQL, strPath)
Dim datCallCount As New DataTable
Dim intCount As Integer = 0
'LiveCalls() variables
Dim strSQLLive As String = "SELECT * FROM tblcallLog WHERE callLive=True"
Dim odaCallsLive As New OleDb.OleDbDataAdapter(strSQLLive, strPath)
Dim datCallLive As New DataTable
Dim intCallLiveCount As Integer = 0
Dim decCallLivePct As Decimal
'TransferCalls() variables
Dim strSQLTransfered As String = _
"SELECT * FROM tblcallLog WHERE callName LIKE '% transfer %' OR callName LIKE 'transfer%'"
Dim odaCallsTransfered As New OleDb.OleDbDataAdapter(strSQLTransfered, strPath)
Dim datCallTransfered As New DataTable
Dim intCallTransfered As Integer = 0
Dim decCallTranfered As Decimal
'SingleStaffCall() Variables
Dim strSQLSingleStaff As String = _
"SELECT * FROM tblcallLog WHERE callName LIKE '% single %' OR callName LIKE 'single%'"
Dim odaCallSingleStaff As New OleDb.OleDbDataAdapter(strSQLSingleStaff, strPath)
Dim datCallSingleStaff As New DataTable
Dim intCallSingleStaff As Integer = 0
Dim decCallSingleStaff As Decimal
'SingleStaffCallsLive() Variables
Dim strSQLSingleStaffLive As String = _
"SELECT * FROM tblcallLog WHERE callName LIKE '% single %' OR callName LIKE 'single%' AND callLive=True"
Dim odaCallSingleStaffLive As New OleDb.OleDbDataAdapter(strSQLSingleStaffLive, strPath)
Dim datCallSingleStaffLive As New DataTable
Dim intCallSingleStaffLive As Integer = 0
Dim decCallSingleStaffLive As Decimal
'CallToday() Variables
Dim strSQLToday As String = _
"SELECT * FROM tblcallLog WHERE startDate = date()"
Dim odaCallToday As New OleDb.OleDbDataAdapter(strSQLToday, strPath)
Dim datCallToday As New DataTable
Dim intCallToday As New Integer
'CallTodayLive() Variables
Dim strSQLTodayLiveCalls As String = _
"SELECT * FROM tblcallLog WHERE callLive=TRUE AND startDate = date()"
Dim odaCallTodayLive As New OleDb.OleDbDataAdapter(strSQLTodayLiveCalls, strPath)
Dim datCallTodayLive As New DataTable
Dim intCallTodayLive As New Integer
Dim decCallTodayLive As New Decimal
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Count()
LiveCalls()
TransferCalls()
SingleStaffCalls()
SingleStaffCallsLive()
CallToday()
CallTodayLive()
End Sub
Private Sub btnUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpdate.Click
'Checks the database for updates when user pushes the update button on the static data tab.
Count()
LiveCalls()
TransferCalls()
SingleStaffCalls()
SingleStaffCallsLive()
CallToday()
CallTodayLive()
End Sub
Private Sub Count()
'database connect and call count
odaCalls.Fill(datCallCount)
odaCalls.Dispose()
intCount = datCallCount.Rows.Count
lblTotalCallsData.Text = intCount.ToString
lblTotalCallsData.Visible = True
End Sub
Private Sub LiveCalls()
'determine number of live calls
odaCallsLive.Fill(datCallLive)
odaCallsLive.Dispose()
intCallLiveCount = datCallLive.Rows.Count
lblcallsLiveData.Text = intCallLiveCount.ToString
lblcallsLiveData.Visible = True
decCallLivePct = intCallLiveCount / intCount
lblPctCallsLiveData.Text = decCallLivePct.ToString("P")
lblPctCallsLiveData.Visible = True
End Sub
Private Sub TransferCalls()
'determine the number of transfer calls
odaCallsTransfered.Fill(datCallTransfered)
odaCallsTransfered.Dispose()
intCallTransfered = datCallTransfered.Rows.Count
lblTotalTransferCallsData.Text = intCallTransfered.ToString
lblTotalTransferCallsData.Visible = True
decCallTranfered = intCallTransfered / intCount
lblPctTransferCallsData.Text = decCallTranfered.ToString("P")
lblPctTransferCallsData.Visible = True
End Sub
Private Sub SingleStaffCalls()
'determine the number of single staff calls and percentage of total
odaCallSingleStaff.Fill(datCallSingleStaff)
odaCallSingleStaff.Dispose()
intCallSingleStaff = datCallSingleStaff.Rows.Count
lblTotalSingleStaffCallData.Text = intCallSingleStaff.ToString
lblTotalSingleStaffCallData.Visible = True
decCallSingleStaff = intCallSingleStaff / intCount
lblPctSingleStaffCallsData.Text = decCallSingleStaff.ToString("P")
End Sub
Private Sub SingleStaffCallsLive()
'determine the percentage of single staff calls taken live
odaCallSingleStaffLive.Fill(datCallSingleStaffLive)
odaCallSingleStaffLive.Dispose()
intCallSingleStaffLive = datCallSingleStaffLive.Rows.Count
decCallSingleStaffLive = intCallSingleStaffLive / intCount
lblPctSingleStaffCallsLiveData.Visible = True
lblPctSingleStaffCallsLiveData.Text = decCallSingleStaffLive.ToString("P")
End Sub
Private Sub CallToday()
'determine values for todays date
odaCallToday.Fill(datCallToday)
odaCallToday.Dispose()
intCallToday = datCallToday.Rows.Count
lblTotalCallsTodayData.Text = intCallToday
lblTotalCallsTodayData.Visible = True
End Sub
Private Sub CallTodayLive()
'determine the number of live calls today
odaCallTodayLive.Fill(datCallTodayLive)
odaCallTodayLive.Dispose()
intCallTodayLive = datCallTodayLive.Rows.Count
lblCallsTodayLiveData.Text = intCallTodayLive.ToString
lblCallsTodayLiveData.Visible = True
'Statement to error correct so the database doesn't force the program to divide by zero
Try
decCallTodayLive = intCallTodayLive / intCallToday
Catch Exception As DivideByZeroException
lblPctCallsTodayLiveData.Text = "0.00%"
lblPctCallsTodayLiveData.Visible = True
Catch Exception As OverflowException
decCallTodayLive = 0
End Try
lblPctCallsTodayLiveData.Text = decCallTodayLive.ToString("P")
lblPctCallsTodayLiveData.Visible = True
End Sub
End Class
The problem is that you are disposing the dataadapters immediately after filling them.
This is why it works on form load, but not after. It would be better practice to create the and destroy the dataadapters in the methods where they are used instead of creating them on spec at the form level.