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