I want to insert 1500 rows to Ms access database from vb.net datagridview.
Inserting up to 400 rows no issue, but above 400 rows its showing error - System resource
Because of the loop, you are creating up to 2 OleDbCommand
objects per row (one for the SELECT
and maybe one for the UPDATE
), but never disposing of them. You could use cmd.Parameters.Clear
to reuse them, but I would chop that thing up into a control procedure to make it simpler. Something like this:
' if AllowUsersToAddRows is true, this will loop one too many:
For x As Integer = 0 To IncomingMailDGV.Rows.Count - 1
Dim received = IncomingMailDGV.Rows(x).Cells(0).Value.ToString
Dim contents = IncomingMailDGV.Rows(x).Cells(2).Value.ToString
Dim subject = IncomingMailDGV.Rows(x).Cells(1).Value.ToString
If ItemExists(received, contents) = False Then
InsertItem(received, contents, subject)
End If
Next
Then helpers which are self contained and clean up after themselves:
Private Function ItemExists(received As String,
contents As String) As Boolean
Dim query As String = "SELECT ReceivedDateTime, Subject, MessageContents FROM IncomingAlerts WHERE ReceivedDateTime = @ReceivedDateTime AND MessageContents =@MessageContents"
Using dbcon As New OleDbConnection(connstr)
dbcon.Open
Using cmd As New OleDbCommand(query, dbcon)
cmd.Parameters.AddWithValue(("ReceivedDateTime", received)
cmd.Parameters.AddWithValue("MessageContents", contents)
' Better to convert the query to a SELECT COUNT
' cmd.ExecuteScalar would not require a Reader
Using rdr = cmd.ExecuteReader
Return rdr.HasRows
End Using
End Using
End Using
End Function
Private Function InsertItem(received As String,
contents As String, subj As String) As Boolean
Dim sql = "INSERT INTO IncomingAlerts(ReceivedDateTime, Subject, MessageContents) Values (@ReceivedDateTime, @Subject, @MessageContents)"
Dim rows As Integer
Using dbcon As New OleDbConnection(connstr)
Using cmd As New OleDbCommand(sql, dbcon)
dbcon.Open
cmd.Parameters.AddWithValue("@ReceivedDateTime", received)
cmd.Parameters.AddWithValue("@Subject", subj)
cmd.Parameters.AddWithValue("@MessageContents", contents)
rows = cmd.ExecuteNonQuery
Return rows <> 0
End Using
End Using
End Function
I also made them a little shorter by using the constructor overloads. For instance, with OleDbCommand, I pass the SQL and the connection to it when it is created rather than set those properties individually.
As is, it gets done only once. There are other things you could do such as just use SQL Count
to determine if the are any matching rows etc. Using a DataTable and FindRow would also prevent having to hot the DB to see if something exists.
The main point is disposing of Connection
, Command
and DataReader
objects when you are done with them.