Я не могу полностью ответить на этот вопрос, потому что вы не показали нам способ выполнения запроса SQL в вашей базе данных, который правильно обрабатывает параметры. Код, который у вас есть, включая метод ExecuteSQL()
, ужасно сломан и потерпит неудачу всякий раз, когда имя или аббревиатура содержит, например, одинарную кавычку как часть значения.
Конечно, вы можете избежать этого ... но это просто один способ ввода нескольких пользователей может сломать ваш SQL. Хуже того, злоумышленники могут использовать это для того, чтобы очень плохие вещи происходили в вашей базе данных.
Итак, вместо этого я написал это, демонстрируя некоторые хорошие практики, включая параметризованные запросы и all- sql upsert . Вам нужно будет заполнить строку подключения и исправить информацию о столбце. Более того, вам нужно применить этот шаблон во всем приложении! Да, это будет означать обновление метода ExecuteSQL()
.
ЭТОТ МАТЕРИАЛ ВАЖЕН!
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim SQL As STring = _
"BEGIN TRY
INSERT INTO TBL_Stream (Name, Abbrev) VALUES (@Name, @Abbrev);
END TRY
BEGIN CATCH
-- ignore duplicate key errors, throw the rest.
IF ERROR_NUMBER() IN (2601, 2627)
UPDATE TBL_Stream
SET Abbrev = @Abbrev
WHERE Name = @Name;
END CATCH"
Using cn As New SqlConnection(" connection string here "), _
cmd As New SqlCommand(SQL, cn)
'I have to guess at type and length. You should use the actual type and length from the database
Dim name As SqlParameter = cmd.Parameters.Add("@Name", SqlDbType.NVarChar, 50)
Dim abbrev As SqlParameter = cmd.Parameters.Add("@Abbrev", SqlDbType.NVarChar, 10)
cn.Open()
For Each row As DataGridViewRow In DataGridView1.Rows
If Not row.IsNewRow Then
name.Value = row.Cells(0).Value
abbrev.Value = row.Cells(1).Value
cmd.ExecuteNonQuery()
End If
Next row
End Using
GetGrid()
MsgBox("Record Saved", MsgBoxStyle.Information, "Saved")
End Sub
Теперь давайте поработаем над обновлением, чтобы лучше поддерживать это в вашем приложении.
Сначала создайте новый Module
. Мы переместим вещи туда, чтобы мы могли обеспечить, чтобы весь доступ к базе данных проходил через наш новый, безопасный шаблон. Затем мы можем сделать наш новый метод private внутри модуля, что еще больше уменьшит искушение писать плохие запросы. Наконец, каждый запрос, который вам нужно выполнить, получит свой собственный метод publi c в модуле. Теперь доступ к вашей базе данных будет больше похож на вызов обычных методов.
Вот что я придумал. Есть (пока) три члена этого модуля. Обратите внимание на выбор Publi c vs Private, потому что они важны для достижения всех целей здесь:
Public Module DB
Private Property ConnectionString As String = " connection string here "
Private Function ExecuteSQL(SQL As String, Params Parameters() As SqlParameter) As DataTable
Dim result As New DataTable
'Because of connection pooling it really is better to create a new connection object in most circumstances.
'Don't try to reuse the same connection throughout your app!
Using cn As New SqlConnection(ConnectionString), _
cmd As New SqlCommand(SQL, cn)
If Parameters IsNot Nothing Then
cmd.Parameters.AddRange(Parameters)
End If
cn.Open()
Using rdr As SqlDataReader = cmd.ExecuteReader()
result.Load(rdr)
Return result
End Using
End Using
End Function
'This is just one way to build this method.
' The important thing is all methods here are encouraged to use good parameterization
Public Sub UpsertStream(Name As String, Abbrev As String)
Dim SQL As STring = _
"BEGIN TRY
INSERT INTO TBL_Stream (Name, Abbrev) VALUES (@Name, @Abbrev);
END TRY
BEGIN CATCH
-- ignore duplicate key errors, throw the rest.
IF ERROR_NUMBER() IN (2601, 2627)
UPDATE TBL_Stream
SET Abbrev = @Abbrev
WHERE Name = @Name;
END CATCH"
Dim n As New SqlParameter("@Name", SqlDbType.NVarChar, 50).Value = Name
Dim a As New SqlParameter("@Abbrev", SqlDbType.NVarChar, 10).Value = Abbrev
ExecuteSQL(SQL, n, a)
End Sub
End Module
А вот как использовать его с Button_Click () Метод:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
For Each row As DataGridViewRow In DataGridView1.Rows
If Not row.IsNewRow Then
DB.UpsertStream(row.Cells(0).Value, row.Cells(1).Value)
End If
Next row
GetGrid()
MsgBox("Record Saved", MsgBoxStyle.Information, "Saved")
End Sub
По мере роста приложения вы можете в конечном итоге переместить этот модуль в его собственный проект библиотеки классов, где модуль и метод ExecuteSQL()
объявлены как Friend
вместо Publi c или частный. Затем вы также можете переместить многочисленные методы Publi c в другие новые модули Publi c внутри этой библиотеки классов, чтобы получить логические группировки между функциональными областями.