Как создать новую запись в базе данных Access с помощью Visual Studio 2019 (VB.NET ) Нажатие кнопки

#vb.net #ms-access

#vb.net #ms-access

Вопрос:

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: я очень новичок в кодировании и программировании; извините, если кодирование является некачественным.

Моя цель состоит в том, чтобы мой проект Visual Studio 2019 (с именем Detailing Error Log) добавил новую запись / строку в мою таблицу базы данных Microsoft Access (файл accdb с именем Database1, таблица с именем Data Collection), на основе которой установлены флажки. Я бы хотел, чтобы строки добавлялись, а не удалялись, при каждом нажатии кнопки «Импорт». Затем база данных будет сохранена, а флажки в моем проекте Visual Studio будут сняты. База данных будет использоваться для хранения этих данных до тех пор, пока она не будет использована координирующей программой Visual Studio для подсчета встречаемости определенного текста в течение определенного месяца. Оттуда это будет отображаться в виде графиков.

Я успешно сделал это с помощью Excel; но испытывал слишком большое отставание всякий раз, когда было несколько записей.

Моя проблема в том, что я получаю эту ошибку из моей переменной «dsnewrow«:

System.NullReferenceException: ‘Ссылка на объект не установлена для экземпляра объекта.’ System.Data.DataTableCollection.this[string].get ничего не вернуло.

Итак, я поискал в Google и на форумах по программированию и не нашел ни одного сообщения, которое, по моему мнению, соответствовало бы тому, чего я пытаюсь достичь: добавлению новой записи при каждом нажатии кнопки «Импорт». Правильный ли мой код для добавления новой записи? Я видел несколько разных способов «добавления» новых записей, но, просмотрев похожие сообщения, я подумал, что это мой лучший вариант.

Ниже приведен мой код, спасибо за помощь!:

NEATOL = нет записей на момент регистрации

 Private Sub ConnectionPrep(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

    Dim dbProvider As String
    Dim dbSource As String
    Dim sql As String
    Dim inc As Integer
    Dim MaxRows As Integer
    Dim con As New OleDb.OleDbConnection
    dbProvider = "PROVIDER=Microsoft.ACE.OLEDB.12.0;"
    dbSource = "Data Source = S:softwareMelton SystemDPD amp; DEL (KPI)Database1.accdb; Persist Security Info = False"
    con.ConnectionString = dbProvider amp; dbSource
    con.Open()
End Sub

Private Sub InputInformation(sender As System.Object, e As System.EventArgs) Handles ImporttBUT.Click
    Dim con As New OleDb.OleDbConnection
    Dim ds As New DataSet
    Dim da As OleDb.OleDbDataAdapter
    Dim cb As New OleDbCommandBuilder()
    Dim dsnewrow As DataRow
    dsnewrow = ds.Tables("Data Collection").NewRow()
    dsnewrow.Item("M/Y OF LOG") = Me.MonthList2021.SelectedItem
    dsnewrow.Item("TIME OF LOG") = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss")
    dsnewrow.Item("USER") = UserName
    dsnewrow.Item("STOCK NUMBER") = Me.StockNumberTXTB.Text
    If MissedPartCHKB.Checked = True Then
        dsnewrow.Item("MISSED PART") = Me.MissedPartCHKB.Text
    ElseIf MissedPartCHKB.Checked = False Then
        dsnewrow.Item("MISSED PART") = "NEATOL"
    End If
    If NotInEpicorCHKB.Checked = True Then
        dsnewrow.Item("NOT IN EPICOR") = Me.NotInEpicorCHKB.Text
    ElseIf NotInEpicorCHKB.Checked = False Then
        dsnewrow.Item("NOT IN EPICOR") = "NEATOL"
    End If
    If MissedBuyoutCHKB.Checked = True Then
        dsnewrow.Item("MISSED BUYOUT") = Me.MissedBuyoutCHKB.Text
    ElseIf MissedBuyoutCHKB.Checked = False Then
        dsnewrow.Item("MISSED BUYOUT") = "NEATOL"
    End If
    If NonStockCHKB.Checked = True Then
        dsnewrow.Item("MISSED NON STOCK ITEM") = Me.NonStockCHKB.Text
    ElseIf NonStockCHKB.Checked = False Then
        dsnewrow.Item("MISSED NON STOCK ITEM") = "NEATOL"
    End If
    If MissedSTKItemCHKB.Checked = True Then
        dsnewrow.Item("MISSED STOCK ITEM") = Me.MissedSTKItemCHKB.Text
    ElseIf MissedSTKItemCHKB.Checked = False Then
        dsnewrow.Item("MISSED STOCK ITEM") = "NEATOL"
    End If
    If MissedAutomatedPartCHKB.Checked = True Then
        dsnewrow.Item("MISSED AUTOMATED") = Me.MissedAutomatedPartCHKB.Text
    ElseIf MissedAutomatedPartCHKB.Checked = False Then
        dsnewrow.Item("MISSED AUTOMATED") = "NEATOL"
    End If
    If MissingPrintAfterQTYCHKB.Checked = True Then
        dsnewrow.Item("MISSING PRINTS AFTER QUANTITY") = Me.MissingPrintAfterQTYCHKB.Text
    ElseIf MissingPrintAfterQTYCHKB.Checked = False Then
        dsnewrow.Item("MISSING PRINTS AFTER QUANTITY") = "NEATOL"
    End If
    If MissedPrintsNOTSentChadCHKB.Checked = True Then
        dsnewrow.Item("MISSED PRINT NOT SENT TO CHAD") = Me.MissedPrintsNOTSentChadCHKB.Text
    ElseIf MissedPrintsNOTSentChadCHKB.Checked = False Then
        dsnewrow.Item("MISSED PRINT NOT SENT TO CHAD") = "NEATOL"
    End If
    If OtherCHKB.Checked = True Then
        dsnewrow.Item("OTHER") = Me.OtherTXTB.Text
    ElseIf OtherCHKB.Checked = False Then
        dsnewrow.Item("OTHER") = "NEATOL"
    End If
    If AddedMissingDimCHKB.Checked = True Then
        dsnewrow.Item("ADDED MISSING DIMENSION") = Me.AddedMissingDimCHKB.Text
    ElseIf AddedMissingDimCHKB.Checked = False Then
        dsnewrow.Item("ADDED MISSING DIMENSION") = "NEATOL"
    End If
    If FixedDimensionCHKB.Checked = True Then
        dsnewrow.Item("FIXED DIMENSION") = Me.FixedDimensionCHKB.Text
    ElseIf FixedDimensionCHKB.Checked = False Then
        dsnewrow.Item("FIXED DIMENSION") = "NEATOL"
    End If
    ds.Tables("Counting").Rows.Add(dsnewrow)
    da.Update(ds, "Counting")
    MsgBox("Entry succesfully added to database.")
    MissedPartCHKB.Checked = False
    MissedAutomatedPartCHKB.Checked = False
    NotInEpicorCHKB.Checked = False
    NonStockCHKB.Checked = False
    MissedSTKItemCHKB.Checked = False
    MissedBuyoutCHKB.Checked = False
    MissedPrintsNOTSentChadCHKB.Checked = False
    MissingPrintAfterQTYCHKB.Checked = False
    AddedMissingDimCHKB.Checked = False
    FixedDimensionCHKB.Checked = False
    OtherCHKB.Checked = False
    OtherTXTB.Text = ""
             MonthList2021.SelectedItem = False
End Sub
 

Комментарии:

1. Я думаю, что ваша проблема в этой строке dsnewrow = ds.Tables("Data Collection").NewRow() — вы пытаетесь добавить новую строку в таблицу, которая не существует. Он DataSet никогда не заполнялся таблицами, поэтому ему нечего вам дать, и, следовательно, вам нечего добавлять новую строку

2. @JayV, Если бы я изменил его на «Dim dsnewrow как новый поток данных», возможно, это сработало бы?

3. Сначала вам нужно получить таблицы из базы данных или создать их в памяти, затем, когда вы добавите новую строку, .Net узнает, что вы пытаетесь сделать

4. @JayV У вас есть какие-нибудь примеры кода, используемого для получения таблиц из базы данных? Извините, как я уже сказал в вопросе; Я не очень долго программировал.

5. Прочтите это: technologyuk.net/computing/software-development /…

Ответ №1:

Хорошо, вы близки.

Итак, адаптер данных — вы хотите присвоить ему ДЕЙСТВИТЕЛЬНЫЙ sql-код, а не ПРОСТО имя таблицы.

SqlCommand builder — вы объявляете его — но он подключен и не связан НИ с ЧЕМ ДРУГИМ!!

Итак, вам нужно это:

 Dim con As New OleDb.OleDbConnection(My.Settings.TestDB)
 

Итак, вы создали объект подключения, но не предоставили сведений о подключении. Я предлагаю вам создать эти соединения в настройках — используйте конструктор соединений.

 Dim da As OleDb.OleDbDataAdapter
 

Вы создаете этот адаптер, но ДЛЯ него ТРЕБУЕТСЯ подключение и, что БОЛЕЕ важно, ему ТАКЖЕ требуется некоторый sql.

поскольку мы собираемся добавлять ТОЛЬКО строки, давайте дадим адаптеру инструкцию sql — но такую, которая не возвращает записей, — но нам ВСЕ РАВНО нужно заполнить этот адаптер.

Итак, используйте это:

 Dim da As OleDb.OleDbDataAdapter("SELECT * from [Data Collection] WHERE ID = 0",con)
 

Далее вы создаете конструктор команд (это хорошо), но вы не указали, что он связан или связан с ЧЕМ-либо еще, поэтому вам нужно / нужно это:

 Dim cb As New OleDbCommandBuilder()
 

Становится таким:

 Dim cb As New OleDbCommandBuilder(da)
 

Когда вы выполните описанное выше, для вас будут созданы команды insert, delete, update и select (приятно !!).

Теперь, чтобы добавить новую строку данных?

После того, как мы сделали все вышеописанное, нам нужно загрузить нашу таблицу данных (опять же, она просто сидит там — ни к чему не подключена). Итак, сделайте это:

Однако у вас есть

 Dim ds As New DataSet
 

Нет, нам не нужен «набор» таблиц — вам нужна ОДНА таблица.

Итак, измените выше на

затемнить ds как новую таблицу данных

Теперь давайте заполним (и что более важно) нашу таблицу, связав ее с нашими объектами data connciton.

 da.Fill(ds)
 

Теперь вы МОЖЕТЕ редактировать строки в ds (но у нас их нет !!!).

Теперь мы можем создать совершенно новый отдельный объект строки (как вы сделали), но я, как правило, просто делаю это:

 With ds.Rows.Add
   .item("Some Field Name") = "your value goes here"
   .etc .etc
End With
 

Но вы можете, если хотите, создать совершенно новую отдельную строку. Опять же, эта строка не может быть просто «сама по себе» здесь.

Итак, вы создаете пустую строку таким образом:

         Dim myRow As DataRow = rstTable.Rows.Add
 

Или в вашем случае:
dsnewrow = ds.Rows.Add

После добавления одной строки или нескольких?

Затем вы должны отправить обратно эти новые строки в базу данных.

  da.Update(ds)
 

Теперь обратите внимание, как я использую «ds», но это datatable, а не dataset. Вы «можете» использовать набор данных, но на самом деле он вам не нужен.

И последнее, но не менее важное?

Ну, адаптер, считыватель, объект подключения и sql?

Вы можете использовать ОДИН объект, который содержит ВСЕ 3 из вышеперечисленных. Это сэкономит ваши пальцы, а также несколько переменных.

Итак, я предлагаю такую настройку — поскольку объект подключения, sql и sql-команда находятся в одном объекте.

Итак, это «шаблон», который я использую:

    Using cmdSQL As New OleDbCommand("SELECT * from tblHotels WHERE ID = 0",
                    New OleDbConnection(My.Settings.TestDB))

        Dim da As New OleDbDataAdapter(cmdSQL)
        Dim sqlBuild As New OleDbCommandBuilder(da)

        Dim rstTable As New DataTable
        da.Fill(rstTable)

        With rstTable.Rows.Add
            .Item("HotelName") = "The zoo Hotel."
        End With

        ' add one more row - but with  row var
        Dim MyOneRow As DataRow = rstTable.Rows.Add

        MyOneRow("HotelName") = "The Barn Hotel"
        MyOneRow("City") = "My City"

        ' write BOTH ROWS back to database - all data rows were AND ARE added to rstTable

        da.Update(rstTable)


    End Using
 

Редактировать — ответы на вопрос о комментариях

Как вы оцениваете cmdSQL?

У меня есть либо это:

     Dim cmdSQL As New OleDbCommand
    or I have this
    Dim cmdSQL As OleDbCommand = New OleDbCommand
 

И то, и другое означает одно и то же.
Обратите внимание, что в некоторых случаях я использовал OleDb.OleDbCommand , а в НЕКОТОРЫХ случаях я использовал OleDbCommand (я не использовал OleDB)

Я МОГУ сэкономить несколько пальцев и печатать, и мне не нужно использовать OleDB. в качестве префикса, потому что в верхней части модуля (перед любым кодом) У меня есть это:

 Imports System.Data.OleDb
 

Если я оставлю выше, то мне ПРИДЕТСЯ использовать OleDb., но с вышеупомянутым импортом я могу оставить OleDB. (Префикс OleDB (точка)).

>> Заполнить» не является членом OleDbDataAdapter(),

Так и должно быть. Я предполагаю, что вы делаете это:

     Using cmdSQL As OleDbCommand = New OleDbCommand("SELECT * from tblHotels WHERE ID = 0",
                    New OleDbConnection(My.Settings.TestDB))


        Dim da As New OleDbDataAdapter(cmdSQL)
 

Конечно, выше (объявляется) объект cmdSQL в разделе «использование». Таким образом, вы не можете использовать cmdSQL вне этого блока using / end using.

>> получаю много ошибок, связанных с моей переменной «da»; Значение BC3031 типа ‘OleDbDataAdapter ()’ не может быть преобразовано в ‘OleDbDataAdapter’

Вы объявляете da как

введите описание изображения здесь

Обратите внимание, как в приведенном выше примере я получаю / получаю «заполнение» в качестве метода da в этом случае.

Поскольку вы заметили, что последний мой пример «использования» работает, значит, в вашем коде что-то не так.

Например, у вас есть это:

 Private Sub ConnectionPrep(.............
 

Хорошо, но этот код на 100% отделен и на 100% изолирован от 2-й процедуры, в которой находится ваш код. 2-я подпрограмма не может ни видеть, ни использовать (и не имеет) никакого отношения к этой 2-й опубликованной подпрограмме.

Итак, как, когда и где вы используете первую процедуру?

И нет ОСОБОЙ необходимости помещать эту настройку строки подключения в код.

Для этого используйте настройки проекта.

Например, на этой странице:

введите описание изображения здесь

Итак, когда вы используете вышеупомянутый конструктор соединений? Тогда все поставщики и настройки теперь доступны в ЛЮБОМ МЕСТЕ кода.

Вы можете использовать

 My.Settings.TestDB 
 

Таким образом, приведенное выше, вернет действительную рабочую строку подключения — в данном случае для oleDB.

Комментарии:

1. Альберт, я в замешательстве. Как вы оцениваете cmdSQL? Я следовал вашим первым рекомендациям по кодированию, и я получаю много ошибок, связанных с моей переменной «da»; Значение BC3031 типа ‘OleDbDataAdapter ()’ не может быть преобразовано в ‘OleDbDataAdapter’ — «Fill» не является членом OleDbDataAdapter (), «update» не является членом OleDbDataAdapterи т.д. Я думаю, что если я структурирую код, как в последнем примере, который вы показываете, он будет работать.