Keep GUI responsive during SQL Backup - vb.net

VB.NET 2.0:
I'm issuing a backup command to a SQL server from a VB.NET application. I'm capturing the messages it sends out and appending them to a multiline textbox.
What I'm trying to do, though, is to allow the application to keep responding to GUI control events (mainly so that the user can resize the output window or cancel the backup). So I use BeginExecuteReader and spin in a loop with Application.DoEvents(). But it seems that as soon as the backup starts issuing its print statements, I get IAsyncResult.IsCompleted = True and it drops down to EndExecuteReader, and the GUI is now locked up again. How can I get it to stay in the loop until the backup command completes and yet still get those output statements and keep the GUI responsive? Thanks.
Here's my code:
' Enable retrieve print statements from the server'
AddHandler oConn.InfoMessage, AddressOf LogToBufferHandler
strSQL &= vbNewLine & "begin try"
strSQL &= vbNewLine & " declare #BackupName as varchar(255)"
strSQL &= vbNewLine & " declare #BackupDesc as varchar(255)"
strSQL &= vbNewLine & " declare #backupTime as varchar(50)"
strSQL &= vbNewLine & " set #backupTime = (select convert(datetime, getdate(), 100))"
strSQL &= vbNewLine & " set #BackupName = (SELECT '[' + db_name() + '] Full Backup')"
strSQL &= vbNewLine & " set #BackupDesc = (SELECT 'Automated full backup of [' + db_name() + '] on ' + #backupTime + '.')"
strSQL &= vbNewLine & " "
strSQL &= vbNewLine & " BACKUP DATABASE [#Database#]"
strSQL &= vbNewLine & " TO DISK = #BackupFullPath"
strSQL &= vbNewLine & " WITH stats,"
strSQL &= vbNewLine & " NAME = #BackupName,"
strSQL &= vbNewLine & " DESCRIPTION = #BackupDesc;"
strSQL &= vbNewLine & " select [IsSuccessful] = 1"
strSQL &= vbNewLine & " end try"
strSQL &= vbNewLine & " begin catch"
strSQL &= vbNewLine & " SELECT [IsSuccessful] = 0"
strSQL &= vbNewLine & " end catch"
'Workaround: Backup Database requires the name of the object, not a string'
' and I dont want to use dynamic SQL.'
strSQL = strSQL.Replace("#Database#", sb.InitialCatalog)
oConn.Open()
oCmd = New SqlCommand()
oCmd.Connection = oConn
oCmd.CommandText = strSQL
oCmd.CommandType = CommandType.Text
oCmd.Parameters.AddWithValue("#BackupFullPath", backupFullPath)
oCmd.CommandTimeout = 60 * 5
'Spin until complete, cancel, or timeout'
Dim result As IAsyncResult = oCmd.BeginExecuteReader(CommandBehavior.CloseConnection)
While Not result.IsCompleted
Application.DoEvents()
If blnCancel Then
oCmd.Cancel()
End If
System.Threading.Thread.Sleep(50)
End While
Try
oDataReader = oCmd.EndExecuteReader(result)
oDataTable.Load(oDataReader)
'Get results'
' (unfourtunately, you cannot do BeginExecuteScalar ASync in .Net 2.0,'
' so we are using a DataTable first column, row)'
If oDataTable IsNot Nothing _
AndAlso oDataTable.Rows.Count > 0 _
AndAlso oDataTable.Columns.Contains("IsSuccessful") _
AndAlso oDataTable.Rows(0).Item("IsSuccessful") = 1 Then
eBackupResult = BackupStatus.Succeeded
returnPath = backupFullPath 'Only set return path if the backup succeeded'
Else
eBackupResult = BackupStatus.Failed
End If
Catch ex As Exception
If Not ex.Message.Contains("cancelled by user") Then Throw ex
eBackupResult = BackupStatus.Canceled
End Try

Polling loops (DoEvents) are considered evil for many reasons. It is probably the easiest way for you to switch to BackgroundWorker and abandon the nasty Begin-poll-End scheme.
If you want to keep it, here is the bug: Accepting the reader can be quick but that doesn't mean that all results have arrived (let me illustrate: what if you had queried 1TB of data? - reading that is a long process). You need to Read in an async (polling) way too. Now the thing gets out of hand. Just abandon it.
In other words, oDataTable.Load is blocking which is hard to fix.

You can use TASKS for this. A task is similar in concept to a thread. By putting your code into a task the main thread can continue to run (which is the thread that takes user input and responds to resize commands).
Here's an article that talks more about tasks and has a VB.NET example.
http://www.dotnetcurry.com/ShowArticle.aspx?ID=491
Have fun!

BackGroundWorker and ReportProgress
BackgroundWorker Class

Related

Update Access database using Visual Studio 2015 - VB.net

I am trying to do a simple update to an Access 2016 database. I am using Visual Studio/VB.net. I have been able to do this already on a different form with no issues using the same type of coding (it's pretty basic, it was for a school project but not anymore). I have tried two different ways to do this...using the update table adapter, for example:
MediatorsListTableAdapter.UpdateMediators(MediatorIDTextBox.Text, MediatorNameTextBox.Text, MaskedTextBox1.Text, MaskedTextBox2.Text, DateTimePicker1.Value,
AvailabilityTextBox.Text, EmailTextBox.Text)
Using that method I always get a notImplemented exception thrown even though I have used a similar type of adapter elsewhere. Also I tried using a strung method (I know, not ideal):
saveInfo = "UPDATE mediatorsList(mediatorName, email, mediatorPrimaryPhone, mediatorSecondaryPhone, lastMediationDate, availability)
VALUES('" & MediatorNameTextBox.Text & "','" & EmailTextBox.Text & "','" & MaskedTextBox1.Text & "','" & MaskedTextBox2.Text & "',
'" & DateTimePicker1.Value & "','" & AvailabilityTextBox.Text & "', WHERE mediatorID = '" & MediatorIDTextBox.Text & "') "
But this method gives me the error of Syntax Error in UPDATE statement. Again I have used this method elsewhere with no problems. Below I will post all the code for this form.
Imports System.Data
Imports System.Data.Odbc ' Import ODBC class
Imports System.Data.OleDb
Imports System.Data.SqlClient
Public Class editMediators
Dim NewData As Boolean
Dim objConnection As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\ECRDatabase.accdb")
' create functions for save or update
Private Sub runAccessSQL(ByVal sql As String)
Dim cmd As New OleDbCommand
connect() ' open our connection
Try
cmd.Connection = conn
cmd.CommandType = CommandType.Text
cmd.CommandText = sql
cmd.ExecuteNonQuery()
cmd.Dispose()
conn.Close()
MsgBox("Data Has Been Saved !", vbInformation)
Catch ex As Exception
MsgBox("Error when saving data: " & ex.Message)
End Try
End Sub
Private Sub editMediators_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.MediatorsListTableAdapter.Fill(Me.ECRDatabaseDataSet.mediatorsList) 'loads current mediator information
DateTimePicker1.Value = Today()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click 'update button
NewData = True
alertMsgBox2()
End Sub
Private Sub alertMsgBox2()
Select Case MsgBox("Yes: Saves Changes," & vbNewLine &
"No: Exits the mediator update window without saving," & vbNewLine &
"Cancel: Returns to the mediator update window.", MsgBoxStyle.YesNoCancel, "Update Mediator Information")
Case MsgBoxResult.Yes
MediatorsListBindingSource.EndEdit()
updateMediator()
'intentionally commented out
'MediatorsListTableAdapter.UpdateMediators(MediatorIDTextBox.Text, MediatorNameTextBox.Text, MaskedTextBox1.Text, MaskedTextBox2.Text, DateTimePicker1.Value,
'AvailabilityTextBox.Text, EmailTextBox.Text)
' Me.Close()
Case MsgBoxResult.No
MediatorsListBindingSource.CancelEdit()
Me.Close()
End Select
End Sub
Private Sub updateMediator()
Dim saveInfo As String
If NewData Then
Dim Message = MsgBox("Are you sure you want to update mediator information? ", vbYesNo + vbInformation, "Information")
If Message = vbNo Then
Exit Sub
End If
Try
'Update mediator information
saveInfo = "UPDATE mediatorsList(mediatorName, email, mediatorPrimaryPhone, mediatorSecondaryPhone, lastMediationDate, availability)
VALUES('" & MediatorNameTextBox.Text & "','" & EmailTextBox.Text & "','" & MaskedTextBox1.Text & "','" & MaskedTextBox2.Text & "',
'" & DateTimePicker1.Value & "','" & AvailabilityTextBox.Text & "', WHERE mediatorID = '" & MediatorIDTextBox.Text & "') "
Catch ex As Exception
End Try
Else
Exit Sub
End If
runAccessSQL(saveInfo)
End Sub
There is obviously something I am missing, though I am not sure it is missing from the code. I checked my database fields and set them to string/text fields just to see if I could get it working. At one time, I had two 2 phone number fields that were set to to the wrong data type so you could only enter a number per int32 requirements. I actually had one of these methods working/updating the db several months ago but I can't figure out what happened since. I do know Visual Studio gave me some problems which probably contributed but it's been too long to remember what happened.
I am rather lost on what else to try as this seems like it should work one way or another. Any ideas what to look at and/or try?? Hopefully I can be pointed in the right direction.
Thanks :)
Your update statement is incorrect, the WHERE clause is inside the VALUES() segment, and should be after it.
Try this instead:
(Edited)
saveInfo = "UPDATE mediatorsList SET mediatorName='" & _
MediatorNameTextBox.Text & "', email='" & EmailTextBox.Text & "', .... WHERE " & _
mediatorID = '" & MediatorIDTextBox.Text & "'"
Also be sure to handle the date correctly. I usually force formatting in yyyy/mmm/dd format.

"variable" is not declared error

Image of the error
I am new to Vb.net programing and I need a little help here, I pretend to send info to my database, the first query gives me the id I need and I declare it as "postoid", when I later try to call it (in the insert into part) it says it is not declared, I have googled the problem a hundred times but I couldn't find the answer.
Ps: this code is all in the same private sub
Try
mysqlconn.Open()
queryrow = "Select * from postos where postos_nome ='" & TextBox1.Text & "'"
COMMANDuser1 = New MySqlCommand(queryrow, mysqlconn)
READERuser = COMMANDuser1.ExecuteReader
While READERuser.Read
Dim postoid = READERuser.GetString("postos_id")
End While
mysqlconn.Close()
Catch ex As Exception
End Try
Dim sqlquery As String = "INSERT INTO computadores VALUES (0,'" & pcname.ToUpper & "','" & ip & "','" & so & "','" & cpu & "','" & ram & "','" & gc & "','" & wserial & "','" & mnome & "','" & mserial & "','" & "--- ,,'Inativo','" & empresaid & "','" & postoid & "','" & userid & "')"
Dim sqlcommand As New MySqlCommand
With sqlcommand
.CommandText = sqlquery
.Connection = mysqlconn
.ExecuteNonQuery()
End With
MsgBox("Computador Adicionado")
Dispose()
Close()
Your variable postoid is out-of-scope outside the block it is declared in.
All you need to do is declare it outside the Try structure:
Dim postoid As String = ""
queryrow = "Select postos_id from postos where postos_nome = #PostosNome"
Using COMMANDuser1 As New MySqlCommand(queryrow, mysqlconn)
COMMANDuser1.Parameters.Add("#PostosNome", TextBox1.Text)
mysqlconn.Open()
READERuser = COMMANDuser1.ExecuteReader()
While READERuser.Read
postoid = READERuser.GetString("postos_id")
End While
mysqlconn.Close()
End Using
If postoid <> "" Then
' perform the insert...
I did not actually use Try in that, as you have no code in your Catch block - having no code in the Catch block has the effect of hiding errors. You want to see the errors.
For using SQL parameters, see, e.g., Inserting data into a MySQL table using VB.NET but please use .Add instead of .AddWithValue - the latter will not always work as intended.

Insert SQL Query not executed

I am doing the programming on my computer and it works fine-the program, the database itself, inserting to the database is also working fine. But when I publish it and install the program on another computer. It crashes and does not execute the INSERT command.
Here is my code.
Private Sub cmdBlank_Click(sender As System.Object, e As System.EventArgs) Handles cmdBlank.Click
strTariff1 = txtPart1.Text & " " & txtPName1.Text & " " & txtQty1.Text & " " & txtU1.Text
strTariff2 = txtPart2.Text & " " & txtPName2.Text & " " & txtQty2.Text & " " & txtU2.Text
strTariff3 = txtPart3.Text & " " & txtPName3.Text & " " & txtQty3.Text & " " & txtU3.Text
strTariff4 = txtPart4.Text & " " & txtPName4.Text & " " & txtQty4.Text & " " & txtU4.Text
'strTariff5 = txtPart5.Text & " " & txtPName5.Text & " " & txtQty5.Text & " " & txtU5.Text
Call saveToDb()
frmreportax.Show()
End Sub
Private Function saveToDb()
conn.Close()
Dim cmdAdd, cmdCount, cmdAdd2 As New iDB2Command
Dim sqlAdd, sqlCount, sqlAdd2 As String
Dim curr1, curr2, curr3, curr4 As String
Dim count As Integer
conn.ConnectionString = str
conn.Open()
'Check for duplicate entry
sqlCount = "SELECT COUNT(*) AS count FROM cewe WHERE transport=#transport AND blnum=#blnum"
With cmdCount
.CommandText = sqlCount
.Connection = conn
.Parameters.AddWithValue("#transport", frmPart1.txtTransport.Text)
.Parameters.AddWithValue("#blnum", frmPart1.txtNo.Text)
End With
count = Convert.ToInt32(cmdCount.ExecuteScalar())
If count <> 0 Then
MsgBox("Duplicate Entry: " & frmPart1.txtTransport.Text, vbOKOnly + vbExclamation)
Else
sqlAdd = "INSERT INTO cewe (page) " & _
"VALUES (#page) "
With cmdAdd
.Parameters.AddWithValue("#page", Val(frmPart1.txtPage.Text))
.CommandText = sqlAdd
.Connection = conn
.ExecuteNonQuery()
End With
end if
cmdAdd.Dispose()
cmdAdd2.Dispose()
conn.Close()
end function
Please tell me what I am doing wrong? When I run and install the program on my PC, it works perfectly fine. But when I run/install it on another PC, it crashes after the cmdBlank is clicked.
There could be a number of things causing the issue but the first place to look is any error logs or crash report that may give some indication of the problem. Try debugging or logging to get a better picture. Beyond that there are some small suggestions that may help below.
Does the other computer have access to the database you are pointing to? Is the database connection pointing to localhost? In which case you will want to ensure that you have the same credentials (host, username, password, port etc.) set up on the database server on new computer. Are database drivers installed on new computer? What are the fundamental differences between the two machines?
AS400 iSeries DB2 needs to be updated to version 6.xx.0800 and did the tweak!
Installer can be found here
http://www-03.ibm.com/systems/power/software/i/access/windows_sp.html
Problem solved!

How to read an excel while in use by another user with Oledb?

I have an excel on a shared drive and my application is using an Oledb connection to read data from the excel into a DataGridView.
cn = New System.Data.OleDb.OleDbConnection("provider=Microsoft.ACE.OLEDB.12.0;" + "data source=" + skuPath + ";Extended Properties=""Excel 12.0;HDR=YES;""")
q1 = "select * from [" + year + "$B4:AM300]"
da = New System.Data.OleDb.OleDbDataAdapter(q1, cn)
Try
cn.Open()
da.Fill(ds, "Table1")
Catch e As OleDb.OleDbException
Dim errorMsg As String
Dim i As Integer
errorMsg = ""
For i = 0 To e.Errors.Count - 1
errorMsg += "Index #" & i.ToString() & ControlChars.Cr _
& "Message: " & e.Errors(i).Message & ControlChars.Cr _
& "NativeError: " & e.Errors(i).NativeError & ControlChars.Cr _
& "Source: " & e.Errors(i).Source & ControlChars.Cr _
& "SQLState: " & e.Errors(i).SQLState & ControlChars.Cr
Next i
End Try
cn.Close()
dt = ds.Tables(0)
When the excel file is already open by another user you get this notification in excel:
And in those situations my code returns this error on the last line:
An unhandled exception of type 'System.IndexOutOfRangeException' occurred in System.Data.dll
Additional information: Cannot find table 0.
So i understand is that because the file is in use then the entire connection returns nothing and data table is therefore empty.
I found a few way of determining if a file is in use or not but nothing regarding how to read from a file in use.
Is it possible? and if so how?
Please remember i only need to read the file and if its possible to always open it as a readonly that would awesome!
You can't. You have to close the open file before read it even if you use the ODBC(read only).
Ref: http://forums.asp.net/t/1083489.aspx?open+a+Microsoft+Jet+OLEDB+4+0+connection+to+excel+file+read+only

SQL Program UPDATE Record Error

I'm working in a small SQL Database program. The programs just there to view, edit and update the database records. Everything is working remarkably well considering I've never tried something like this before. I've managed to get the Add Records, Refresh Records and Delete Records functions working flawlessly. However, I've hit a little bump when trying to UPDATE a selected record.
To clarify, the SQL Table is displayed in a list view, from this list view the end-user can select a particular-record and either edit or delete it.
The edit button opens a new form window with text fields which are automatically filled with the current information of that record.
The code for the edit record form is:
Private Sub frmEdit_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
intDB_ID_Selected = CInt(frmMain.lvRec.SelectedItems(0).Text)
Call dispCaption()
Call dispInfo() 'Display the info of the selected ID
End Sub
Private Sub dispInfo()
SQL = "Select * from PersonsA " & _
"where Members_ID=" & intDB_ID_Selected & ""
With comDB
.CommandText = SQL
rdDB = .ExecuteReader
End With
If rdDB.HasRows = True Then
rdDB.Read()
Me.midtxt.Text = rdDB!Members_ID.ToString.Trim
Me.gttxt.Text = rdDB!Gamer_Tag.ToString.Trim
Me.sntxt.Text = rdDB!Screenname.ToString.Trim
Me.fntxt.Text = rdDB!First_Name.ToString.Trim
Me.lntxt.Text = rdDB!Last_Name.ToString.Trim
Me.dobtxt.Text = rdDB!DoB.ToString.Trim
Me.dobtxt.Text = rdDB!DoB.ToString.Trim
Me.emailtxt.Text = rdDB!E_Mail_Address.ToString.Trim
Me.teamptxt.Text = rdDB!Position.ToString.Trim
Me.ugctxt.Text = rdDB!Cautions.ToString.Trim
Me.recordtxt.Text = rdDB!Record.ToString.Trim
Me.eventatxt.Text = rdDB!Event_Attendance.ToString.Trim
Me.Mstattxt.Text = rdDB!Member_Status.ToString.Trim
End If
rdDB.Close()
End Sub
Private Sub dispCaption()
End Sub
Private Sub cmdUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdUpdate.Click
Call disControl()
'Validation
If invalidUpdateEntry() = True Then
Call enaControl()
Exit Sub
End If
'Prompt the user if the record will be updated
If MsgBox("Are you sure you want to update the selected record?", CType(MsgBoxStyle.YesNo + MsgBoxStyle.DefaultButton2 + MsgBoxStyle.Question, MsgBoxStyle), "Update") = MsgBoxResult.Yes Then
'Update query
SQL = "Update PersonsA" & _
"SET Members_ID='" & Me.midtxt.Text.Trim & "'," & _
"Gamer_Tag='" & Me.gttxt.Text.Trim & "'," & _
"Screenname='" & Me.sntxt.Text.Trim & "'," & _
"First_Name='" & Me.fntxt.Text.Trim & "'," & _
"Last_Name='" & Me.lntxt.Text.Trim & "'," & _
"DoB='" & Me.dobtxt.Text.Trim & "'," & _
"E_Mail_Address='" & Me.emailtxt.Text.Trim & "'," & _
"Position='" & Me.teamptxt.Text.Trim & "'," & _
"U_G_Studio='" & Me.ugptxt.Text.Trim & "'," & _
"Cautions='" & Me.ugctxt.Text.Trim & "'," & _
"Record='" & Me.recordtxt.Text.Trim & "'," & _
"Event_Attendance='" & Me.eventatxt.Text.Trim & "'," & _
"Member_Status='" & Me.Mstattxt.Text.Trim & "'" & _
"WHERE Members_ID='" & intDB_ID_Selected & "'"
Call execComDB(SQL) 'Execute the query
Me.Close()
'*** Refresh the list
SQL = "Select * from PersonsA "
Call frmMain.dispRec(SQL)
'--- End of refreshing the list
Exit Sub
Else
Call enaControl()
End If
End Sub
As I've said, I've been able to do everything else using an extremely similar method, but when I try to UPDATE the record I get an error saying
An unhandled exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll
Additional information: Incorrect syntax near 'Members_ID'.
I know it's this line that's the problem
"WHERE Members_ID='" & intDB_ID_Selected & "'"
Call execComDB(SQL) 'Execute the query
But referencing 'intDB_ID_Selected' has always worked before, and it's been set-up on the update form records load as intDB_ID_Selected = CInt(frmMain.lvRec.SelectedItems(0).Text)
I know this is a huge thread but if anyone could steer me in the right direction WITHOUT telling me to re-write the entire statement I'd be forever grateful.
EDIT1: I fixed the comma before the WHERE clause, but I'm still getting the same error.
Missing a space between
"Update PersonsA " & _
"SET Members_ID= ....
and (as already pointed out) a comma not needed before the WHERE
Said that, do a favor to yourself and to your users. Do not use string concatenation to build a sql command. Use always a parameterized query.
Just as an example
SQL = "Update PersonsA SET Members_ID=#id, Gamer_Tag=#tag, Screenname=#screen," & _
"First_Name=#fname,Last_Name=#lname,DoB=#dob,E_Mail_Address=#email," & _
"Position=#pos,U_G_Studio=#studio,Cautions=#caution,Record=#rec," & _
"Event_Attendance=#event, Member_Status=#stat " & _
"WHERE Members_ID=#id"
SqlCommand cmd = new SqlCommand(SQL, connection)
cmd.Parameters.AddWithValue("#id", Me.midtxt.Text.Trim)
..... so on for the other parameters defined above ....
cmd.ExecuteNonQuery();
Change "Member_Status='" & Me.Mstattxt.Text.Trim & "'," & _
to "Member_Status='" & Me.Mstattxt.Text.Trim & "'" & _
Looks like it was just an extra rogue comma!
On any error like this, use debugging provided with Visual Studio. Inspect the value of SQL, paste into MS SQL Management Studio - it has syntax highlight, and you should be able to spot the error easily.
To prevent further issues (including SQL injection vulnerability), separate this query into an embedded resource, and use parameters. Then it's easy to view, maintain (you can copy/paste between SQL Mgmt Studio and VS), and ultimately use it in code.
A side note, you don't need to use Call in VB.NET, just put a method name with parenthesis.