Как вставить и обновить все данные из datagridview до sql datatable - PullRequest
0 голосов
/ 12 марта 2020

Я хочу набрать все данные в сетке данных и вставить в SQL с данными или, если данные существуют, он должен обновить данные в SQL с использованием данных.

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 row.IsNewRow = False Then

            sqlSTR = "SELECT ID, Name, Abbrev FROM TBL_Stream WHERE (Name = '" & row.Cells(0).Value & "')"
            ExecuteSQLQuery(sqlSTR)

            If sqlDT.Rows.Count > 0 Then

                sqlSTR = "UPDATE TBL_Stream SET Name ='" & row.Cells(0).Value & "', Abbrev ='" & row.Cells(1).Value & "' WHERE (Name ='" & row.Cells(0).Value & "')"
                ExecuteSQLQuery(sqlSTR)

                GetGrid()
                MsgBox("Record Updated", MsgBoxStyle.Information, "Update")

            Else

                sqlSTR = "INSERT INTO TBL_Stream (Name, Abbrev) VALUES        ('" & row.Cells(0).Value & "','" & row.Cells(1).Value & "')"
                ExecuteSQLQuery(sqlSTR)

                GetGrid()
                MsgBox("Record Saved", MsgBoxStyle.Information, "Record")

            End If

        End If

    Next

End Sub

Ответы [ 2 ]

1 голос
/ 12 марта 2020

Я не могу полностью ответить на этот вопрос, потому что вы не показали нам способ выполнения запроса 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 внутри этой библиотеки классов, чтобы получить логические группировки между функциональными областями.

0 голосов
/ 12 марта 2020

Я не читал вопрос достаточно внимательно для начала, но вы все еще можете выполнять upserts с помощью адаптера данных и DataTable. Вы просто начинаете с пустого DataTable, добавляете все нужные строки и затем вызываете Update на адаптере данных с соответствующим upsert SQL в InsertCommand, например,

Private adapter As SqlDataAdapter
Private table As DataTable

Private Sub ConfigureDataAccess()
    Dim connection As New SqlConnection("Server=(local);Database=Test;Trusted_Connection=True;")

    adapter = New SqlDataAdapter("SELECT * FROM Table_1", connection)

    Dim upsertSql = "
IF EXISTS (SELECT * FROM Table_1 WHERE Id = @Id)
    UPDATE Table_1 SET Name = @Name WHERE Id = @Id
ELSE
    INSERT INTO Table_1 (Name) VALUES (@Name)"
    Dim upsertCommand As New SqlCommand(upsertSql, connection)

    upsertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id")
    upsertCommand.Parameters.Add("@Name", SqlDbType.VarChar, 50, "Name")

    adapter.InsertCommand = upsertCommand
    table = New DataTable()
End Sub

Private Sub GetSchema()
    adapter.FillSchema(table, SchemaType.Source)
    BindingSource1.DataSource = table
    DataGridView1.DataSource = BindingSource1
End Sub

Private Sub SaveData()
    Validate()
    BindingSource1.EndEdit()
    adapter.Update(table)
End Sub

SQL для вставки и обновления идет в InsertCommand, потому что все DataRows в DataTable будут иметь RowState из Added, поэтому InsertCommand будет выполняться для каждого. В этом примере я вызвал FillSchema, чтобы создать DataTable со схемой, которая соответствует базе данных, но без строк. Вы можете создать свой DataTable, однако, подходит.

...