簡體   English   中英

如何使用 Visual Studio 2019 (VB.NET) 按鈕在 Access 數據庫中創建新記錄

[英]How to Create a New Record in an Access Database using Visual Studio 2019 (VB.NET) Button Click

免責聲明:我對編碼和編程非常陌生; 抱歉,如果編碼低於標准。

我的目標是讓我的 Visual Studio 2019 項目(名為 Detailing Error Log)根據選中的復選框將新記錄/行添加到我的 Microsoft Access 數據庫表(名為 Database1 的 accdb 文件,名為 Data Collection 的表)中。 每當單擊“導入”按鈕時,我只想添加行,而不是刪除行。 然后將保存數據庫,並且取消選中我的 Visual Studio 項目中的復選框。 數據庫將用於存儲該數據,直到協調的 Visual Studio 程序使用它來計算特定月份內特定文本的出現次數。 從那里它將以圖表的形式顯示。

我已經使用 Excel 成功地做到了這一點; 但是每當有多個條目時都會經歷太多的延遲。

我的問題是我從我的“ dsnewrow ”變量中得到這個錯誤:

System.NullReferenceException:“對象引用未設置為 object 的實例。” System.Data.DataTableCollection.this[string].get 沒有返回任何內容。

所以我在谷歌和編程論壇上四處尋找,我並沒有真正找到任何我認為與我想要完成的工作相匹配的帖子:每次單擊“導入”按鈕時添加一條新記錄。 我添加新記錄的代碼是否正確? 我看到了幾種“添加”新記錄的不同方式,但是通過查看類似的帖子,我認為這是我最好的選擇。

以下是我的代碼,感謝您的幫助::

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:\software\Melton System\DPD & DEL (KPI)\Database1.accdb; Persist Security Info = False"
    con.ConnectionString = dbProvider & 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

好的,你很接近。

所以,數據適配器 - 你想給它一個 VALID sql - 而不僅僅是一個表名。

sqlCommand builder - 你聲明它 - 但它與 NOTHING ELSE 相關聯!

所以,你需要這個:

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

因此,您創建了連接 object - 但沒有提供連接的詳細信息。 我建議您在設置中創建該連接 - 使用連接構建器。

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)

當您執行上述操作時,將為您構建插入、刪除、更新和 select 命令(很好。!)。

現在,要添加一個新的數據行?

完成上述所有操作后,我們需要加載我們的數據表(同樣,它只是坐在那里 - 沒有連接到任何東西)。 所以,這樣做:

但是,你有

Dim ds As New DataSet

不,我們不需要“一組”桌子——你需要一張桌子。

所以把上面改成

將 ds 暗淡為新數據表

現在,讓我們填充(更重要的是)將我們的表與我們的數據連接對象相關聯。

da.Fill(ds)

現在您可以在 ds 中編輯行(但我們沒有。!!)。

現在我們可以創建一個全新的單獨行 object (就像你做的那樣),但我傾向於這樣做:

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”的,但它是一個數據表而不是數據集。 您“可以”使用數據集 - 但實際上,您不需要數據集。

另外,最后但並非最不重要的是?

那么,適配器、閱讀器、object 和 sql 的連接?

您可以使用包含以上所有 3 個的 object。 這將節省您的手指,以及幾個變量。

所以,我建議這種設置 - 因為連接 object 和 sql 和 sql 命令都在一個 ZA8CFDE6331BD54B66AC96F8911C 中。

所以,這是我使用的“模板”:

   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(點)前綴)。

>>Fill" 不是 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 object。 因此,您不能在 using/end using 塊之外使用 cmdSQL。

>>得到許多與我的變量“da”相關的錯誤; BC3031 類型“OleDbDataAdapter()”的值無法轉換為“OleDbDataAdapter”

您將 da 聲明為

在此處輸入圖像描述

請注意,在這種情況下,我如何在上面獲取/擁有“填充”作為 da 的方法。

由於您注意到我的最后一個“使用”示例有效,因此您的代碼中出現了一些問題。

例如,你有這個:

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

好的,但是該代碼是 100% 獨立的,並且與您的代碼所在的第二個例程 100% 隔離。 第二個例程看不到,也不使用(也沒有)與第二個發布的例程有任何關系。

那么如何、何時、何地使用第一個例程?

並且幾乎不需要將該連接字符串設置放入代碼中。

為此使用項目設置。

例如這個頁面:

在此處輸入圖像描述

那么,當您使用上述連接構建器時呢? 然后,所有提供程序和設置現在都可以在代碼中的任何地方使用。

您可以使用

My.Settings.TestDB 

因此,上面將返回一個有效的工作連接字符串 - 在這種情況下為 oleDB。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM