how to unzip more than one zip file and delete it - vb.net

When i am geting more than one zip file i can't unzip the second zip file
For example there is a .tif inside the zip file, when its loopign the unzip funcion its say the .tif is already exists.
Try
If Not Directory.Exists(extractPath) Then
Directory.CreateDirectory(extractPath)
End If
Using archive As ZipArchive = ZipFile.OpenRead(zipPath)
For Each entry As ZipArchiveEntry In archive.Entries
ZipFile.ExtractToDirectory(zipPath & DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), extractPath)
Next
End Using
Using cn As New SqlConnection(dl.getconnstr)
cn.Open()
Using tran As SqlTransaction = cn.BeginTransaction
Using cmd As New SqlCommand("", cn, tran)
cmd.CommandText = "UPDATE tableXXX SET unziped='Y' WHERE attachfile='" + zipPath + "'"
cmd.ExecuteNonQuery()
End Using
End Using
End Using
Catch ex As Exception
Using cn As New SqlConnection(dl.getconnstr)
cn.Open()
Using tran As SqlTransaction = cn.BeginTransaction
Using cmd As New SqlCommand("", cn, tran)
cmd.CommandText = "UPDATE tableXXX SET unziped='N' WHERE attachfile='" + zipPath + "'"
cmd.ExecuteNonQuery()
End Using
End Using
End Using
End Try

Your loop doesn't really make sense. If you're going to do this:
For Each entry As ZipArchiveEntry In archive.Entries
then you're supposed to use entry inside the loop to extract that one entry. ZipFile.ExtractToDirectory extracts all entries in an archive to a directory, so it should be obvious that you would only call that once per archive. What you are doing is extracting every entry once for every entry that is in the archive, e.g. if there are 10 entries then you extract all 10 entries 10 times. Obviously that makes no sense and that's why you are being told something already exists on the second iteration: because you just created it on the previous iteration.
You need to decide whether you want to use a loop or ZipFile.ExtractToDirectory and do just that. You don't use both.

Related

VB SQL DELETE Statement Not Working - No Error At All

This is my Code and it just doesn't work, I'm trying to make it Delete a record where the column staffID is equal to the variable currentStaffID although it doesn't delete the record or give an error, it just carries on and displays the MsgBox after the DELETE Statement.
Dim AreYouSureEdit = MsgBox("Are you sure you want to delete this record?", MsgBoxStyle.YesNo)
If DbConnect() And AreYouSureEdit = MsgBoxResult.Yes Then
Dim SQLCmd As New OleDbCommand
SQLCmd.Connection = cn
currentStaffID = editStaffIDTxtBox.Text()
SQLCmd.CommandText = "DELETE * STAFF WHERE staffID = #currentStaffID"
cn.Close()
MsgBox("Record Deleted.", MsgBoxStyle.OkOnly)
End If
You're setting up your command and everything - but you're never executing it! Of course nothing happens.....
You need to add one line of code:
Dim SQLCmd As New OleDbCommand
SQLCmd.Connection = cn
currentStaffID = editStaffIDTxtBox.Text()
SQLCmd.CommandText = "DELETE * STAFF WHERE staffID = ?"
'' You need to define the parameter and set its value here!
SQLCmd.Parameters.Add("p1", OleDbType.Int).Value = currentStaffID;
'' you need to actually **EXECUTE** your DELETE query!
SQLCmd.ExecuteNonQuery()
cn.Close()
Also, while you're setting up a parameter in your SQL query text just fine, I don't see where you're actually defining such a parameter on your SQLCmd object - and also be aware: OleDB doesn't use named parameters (like the native SQL Server client does) - it uses positional parameters (so that's what I replaced your named parameter with just a ?). Since there's only one parameter, this shouldn't be a problem here - but you need to properly define the SQLCmd's parameter (and set its value)
Connections and Commands can use unmanaged resources so, they need to have their .Dipose methods called to release these resources. Using...End Using blocks take care of this and also .Close the connection. Your database objects must be local to the method where they are used for this to work.
Always use Parameters to avoid Sql injection.
Private Sub OpCode()
Dim AreYouSureEdit = MsgBox("Are you sure you want to delete this record?", MsgBoxStyle.YesNo)
If AreYouSureEdit = MsgBoxResult.Yes Then
Using cn As New OleDbConnection("Your connection string"),
SQLCmd As New OleDbCommand("DELETE From STAFF WHERE staffID = #currentStaffID", cn)
SQLCmd.Parameters.Add("#currentStaffID", OleDbType.Integer).Value = CInt(editStaffIDTxtBox.Text)
cn.Open()
SQLCmd.ExecuteNonQuery()
End Using
MsgBox("Record Deleted.", MsgBoxStyle.OkOnly)
End If
End Sub

Performance issue with SQLite database with VB.NET

I am Inserting the data-table into SQLite Database. I am doing like this.
First I Fetch the data with getdata function and insert it into datatable, then with For Each Loop i made the Insert Command and Execute It. I am having 50000 Records it will take 30 Minutes to run.
Please Guide the suitable approach. Here is the Code.
Dim xtable As DataTable = getdata("select * from tablename")
Dim str As String = Nothing
For Each r As DataRow In xtable.Rows ''''HERE IT WILL TAKE TOO MUCH TIME
str = str & ("insert into tablename values(" & r.Item("srno") & "," & r.Item("name"));")
Next
EXECUTEcmd(str)
Public Function getdata(ByVal Query As String) As DataTable
connectionString()
Try
Dim mds As New DataTable
Dim mycommand As New SQLiteCommand(DBConn)
mycommand.CommandText = Query
Dim reader As SQLiteDataReader = mycommand.ExecuteReader()
mds.Load(reader)
Return mds
Catch ex As Exception
MsgBox("DB Error", vbCritical, "")
MsgBox(Err.Description)
Return Nothing
End Try
End Function
Public Sub EXECUTEcmd(ByVal selectcmd As String)
Using cn = New SQLiteConnection(conectionString)
cn.Open()
Using transaction = cn.BeginTransaction()
Using cmd = cn.CreateCommand()
cmd.CommandText = selectcmd
cmd.ExecuteNonQuery()
End Using
transaction.Commit()
End Using
cn.Close()
End Using
End Sub
here the Conncection String is:
conStr = "Data Source=" & dbpath & ";Version=3;Compress=True; UTF8Encoding=True; PRAGMA journal_mode=WAL; cache=shared;"
Use a stringbuilder to build your string, not string concatenation
Dim strB As StringBuilder = New StringBuilder(100 * 50000)
For Each r As DataRow In xtable.Rows
strB.AppendLine($"insert into tablename values({r.Item("srno")},{r.Item("name")});")
Next
Strings cannot be changed in .net. Every time you make a new string VB has to copy everything out of the old string into a new one and add the new bit you want. If each of your insert statements is 100 bytes, that means it copies 100 bytes, then adds 100, then copies 200 bytes and adds 100, then copies 300 bytes, then 400 bytes, then 500 bytes. By the time it has done 10 strings it has made 5.5 kilobytes of copying. By the time it's done 50 thousand strings it has copied 125 gigabytes of data. No wonder it's slow!
Always use a StringBuilder to build massive strings
--
I'm willing to overlook the sql injection hacking nag for this one, because of the nature of the task, but please read http://bobby-tables.com - you should never, ever concatenate values into an SQL as a way of making an sql that has some varying effect.
This entire exercise would be better done as this (pseudocode) kind of thing:
Dim sel as New SQLiteCommand("SELECT a, b FROM table", conn)
Dim ins as New SQLiteCommand("INSERT INTO table VALUES(:a, :b)", conn)
ins.Parameters.Add("a" ...)
ins.Parameters.Add("b" ...)
Dim r = sel.ExecuteReader()
While r.Read()
ins.Parameters("a") = r.GetString(0)
ins.Parameters("b") = r.GetString(1)
ins.ExecuteNonQuery()
End While
That is to say, you minimize your memory by reading rows one at a time out of ther edaer and inserting them one at a time in the insert; the insert command is prepared once, you just change the parameter values, execute it, change them again, execute it ... It's what parameterized queries were designed for (as well as stopping your app getting hacked when someone puts SQL in your variable, or even just stopping it crashing when you have an person named O'Grady
Maybe you must refactor your code like this:
Dim xtable As DataTable = getdata("select * from tablename")
Using cn = New SQLiteConnection(conectionString)
cn.Open()
Using transaction = cn.BeginTransaction()
Try
Using cmd = cn.CreateCommand()
cmd.Transaction = transaction
For Each r As DataRow In xtable.Rows ''''HERE IT WILL TAKE TOO MUCH TIME
cmd.CommandText = "insert into tablename values(" & r.Item("srno") & "," & r.Item("name") & ")"
cmd.ExecuteNonQuery()
Next
End Using
transaction.Commit()
Catch ex As Exception
transaction.Rollback()
End Try
End Using
End Using
Public Function getdata(ByVal Query As String) As DataTable
connectionString()
Try
Dim mds As New DataTable
Dim mycommand As New SQLiteCommand(DBConn)
mycommand.CommandText = Query
Dim reader As SQLiteDataReader = mycommand.ExecuteReader()
mds.Load(reader)
Return mds
Catch ex As Exception
MsgBox("DB Error", vbCritical, "")
MsgBox(Err.Description)
Return Nothing
End Try
End Function
Instead of concatenate an possible giant string, wrap all your inserts into a single transaction, like above. This will reduce the memory used and also make sqlite perform faster.

Renaming files when saving to location

I am using the below code to copy a file to a network location and store the file information in an access database.
Dim SqlString1 As String = "INSERT INTO document (incidentid, documentno, documentname, documentpath) VALUES (#incid, #docid, #FileName, #FilePath)"
Using conn As New OleDbConnection(ConnString)
conn.Open()
If Me.TextBox1.Text <> "" Then
'THIS WILL SAVE THE FILE TO A LOCATION
Dim fileLocation As String = OpenFileDialog1.FileName
File.Copy(fileLocation, Path.Combine("\\10.1.10.5\NonConformance\Document\", Path.GetFileName(fileLocation)), True)
'THIS WILL SAVE A FILE PATH TO THE ACCESS DB
Using cmd As New OleDbCommand(SqlString1, conn)
'cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("#incid", doc1.Text)
cmd.Parameters.AddWithValue("#docid", doc2.Text)
cmd.Parameters.AddWithValue("#FileName", Path.GetFileName(Me.OpenFileDialog1.FileName))
cmd.Parameters.AddWithValue("#FilePath", "\\10.1.10.5\NonConformance\Document\" & Path.GetFileName(Me.OpenFileDialog1.FileName))
cmd.ExecuteNonQuery()
conn.Close()
End Using
End If
conn.Close()
End Using
I am concerned that if a user uploads a file with the same filename as one already in the folder it will cause issues when trying to retrieve information at a later date.
So can anyone tell me how to rename the file when copying it to the network location. Ideally I would like to rename it to be the #incid_#docid parameters
I ended up changing the
Path.GetFileName(fileLocation))
element to read
Path.GetFileName("INC" & Label6.Text & "DOC" & doc2.Text & ".pdf")
This will solve the issue for me, thanks for the responses.

How do I assign the results of an SQL query to multiple variables in VB.NET?

This is my first attempt at writing a program that accesses a database from scratch, rather than simply modifying my company's existing programs. It's also my first time using VB.Net 2010, as our other programs are written in VB6 and VB.NET 2003. We're using SQL Server 2000 but should be upgrading to 2008 soon, if that's relevant.
I can successfully connect to the database and pull data via query and assign, for instance, the results to a combobox, such as here:
Private Sub PopulateCustomers()
Dim conn As New SqlConnection()
Dim SQLQuery As New SqlCommand
Dim daCustomers As New SqlDataAdapter
Dim dsCustomers As New DataSet
conn = GetConnect()
Try
SQLQuery = conn.CreateCommand
SQLQuery.CommandText = "SELECT Customer_Name, Customer_ID FROM Customer_Information ORDER BY Customer_Name"
daCustomers.SelectCommand = SQLQuery
daCustomers.Fill(dsCustomers, "Customer_Information")
With cboCustomer
.DataSource = dsCustomers.Tables("Customer_Information")
.DisplayMember = "Customer_Name"
.ValueMember = "Customer_ID"
.SelectedIndex = -1
End With
Catch ex As Exception
MsgBox("Error: " & ex.Source & ": " & ex.Message, MsgBoxStyle.OkOnly, "Connection Error !!")
End Try
conn.Close()
End Sub
I also have no problem executing a query that pulls a single field and assigns it to a variable using ExecuteScalar. What I haven't managed to figure out how to do (and can't seem to hit upon the right combination of search terms to find it elsewhere) is how to execute a query that will return a single row and then set various fields within that row to individual variables.
In case it's relevant, here is the GetConnect function referenced in the above code:
Public Function GetConnect()
conn = New SqlConnection("Data Source=<SERVERNAME>;Initial Catalog=<DBNAME>;User Id=" & Username & ";Password=" & Password & ";")
Return conn
End Function
How do I execute a query so as to assign each field of the returned row to individual variables?
You probably want to take a look at the SqlDataReader:
Using con As SqlConnection = GetConnect()
con.Open()
Using cmd As New SqlCommand("Stored Procedure Name", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("#param", SqlDbType.Int)
cmd.Parameters("#param").Value = id
' Use result to build up collection
Using dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection Or CommandBehavior.SingleResult Or CommandBehavior.SingleRow)
If (dr.Read()) Then
' dr then has indexed columns for each column returned for the row
End If
End Using
End Using
End Using
Like #Roland Shaw, I'd go down the datareader route but an other way.
would be to loop through
dsCustomers.Tables("Customer_Information").Rows
Don't forget to check to see if there are any rows in there.
Google VB.Net and DataRow for more info.

Deleting from sqlite database using IN

I am deleting from an sqlite database using the ids of the records like this
(the dirID is an array of the IDs):
Dim i As Integer = 0
Dim conn As New SQLiteConnection("Data Source=" & DBPath)
Dim cmd As New SQLiteCommand("DELETE FROM directory WHERE id IN (#ID)", conn)
cmd.Parameters.AddWithValue("#ID", Join(dirID, ","))
'conn.SetPassword(dbPassword)
conn.Open()
Try
mytransaction = conn.BeginTransaction()
'// delete directory //
If dirID IsNot Nothing Then
cmd.ExecuteNonQuery()
End If
mytransaction.Commit()
conn.Close()
Catch ex As Exception
mytransaction.Rollback()
strLastError = ex.Message
Debug.Print(strLastError)
Finally
cmd.Dispose()
conn.Dispose()
End Try
The problem is that it doesn't always delete from the database, and its not throwing any errors.
Could there be a better way of deleting?
That's not how parameters work.
If your IN list is 1, 2, 3, the command is trying to delete the record where ID equals "1, 2, 3", which is none. So no error is thrown and no record is deleted, because none was found. Thus, you will also find out that your code only works when your list contains 1 item.
Solution: You have to build your delete query (string manipulation), instead of working with parameters. Just beware of SQL Injection.
Update
From your code, it would be something like that:
Dim delcmd = "DELETE FROM directory WHERE id IN (" + Join(dirID, ",") + ")"
Dim cmd As New SQLiteCommand(delcmd, conn)
And no parameter call. Beware: I just tweaked your code, but it is not SQL Injection safe. You should read about that and about what's been written on the subject here in StackOverflow.