出现在控制源不是 PK 字段的文本框中的记录的主键

Posted

技术标签:

【中文标题】出现在控制源不是 PK 字段的文本框中的记录的主键【英文标题】:Primary Key for record appearing in textbox where Control Source is not PK field 【发布时间】:2017-08-17 16:23:09 【问题描述】:

我在使用 Access 2010 数据库时遇到问题,当我移动到链接表单上的另一个控件时,新记录的主键也被添加到不相关的字段中。

我的最小数据库由一个名为Teams 的表组成。表中有四个字段:

+-----------------+-----------+-----------+--------------+
|     TeamID      | TeamName  | CostCode  |  SortOrder   |
+-----------------+-----------+-----------+--------------+
| AutoNumber (PK) | Text(255) | Text(255) | Long Integer |
+-----------------+-----------+-----------+--------------+  

此表通过Record Source 链接到名为Edit_Teams 的表单。 表单上有三个控件:

+-----------------+-------------+-----------+------------------------------------+
|    Control:     |   TextBox   |  TextBox  |              ComboBox              |
+-----------------+-------------+-----------+------------------------------------+
| Name:           | txtCostCode | txtTeamID | cmbTeamName                        |
| Control Source: | CostCode    | TeamID    | -                                  |
| Row Source:     | -           | -         | SELECT TeamID, TeamName FROM Teams |
+-----------------+-------------+-----------+------------------------------------+  

combobox 绑定到第 1 列,Limit To List = Yes

当您在记录之间移动时,表单有一些代码可以使组合框与表单的其余部分保持同步:

Private Sub Form_Current()
    If Not IsNull(Me.txtTeamID) Then
        Me.cmbTeamName.Requery
        Me.cmbTeamName = Me.txtTeamID
        If Me.cmbTeamName <> 0 Then
            'Some other code that adds stuff to a subform.
            Me.Refresh
        End If
    Else
        Me.cmbTeamName = 0
    End If
End Sub  

组合框有两个事件:

Private Sub cmbTeamName_AfterUpdate()
    If Me.cmbTeamName = "0" Then
        DoCmd.GoToRecord , , acNewRec
    Else
        GoToBookmark Me, "TeamID", cmbTeamName
        If cmbTeamName <> 0 Then
            'Some other code that adds stuff to a subform.
            Me.Refresh
        End If
    End If
End Sub  

Private Sub cmbTeamName_NotInList(NewData As String, Response As Integer)
    With DoCmd
        .SetWarnings False
        If MsgBox("Add '" & NewData & "' as a new team?", vbYesNo + vbQuestion) = vbYes Then
            .RunSQL "INSERT INTO Teams(TeamName, CostCode, SortOrder) " & _
                    "VALUES ('" & NewData & "', Null," & DCount("TeamID", "Teams") + 1 & ")"
            Response = acDataErrAdded
            Me.cmbTeamName = Me.cmbTeamName.ItemData(0) 'Move to an item that exists so Requery doesn't fire NotInList.
            Me.Requery
            GoToBookmark Me, "TeamName", NewData
            Me.cmbTeamName.Requery
            Me.cmbTeamName = DLookup("TeamID", "Teams", "TeamName='" & TeamName & "'")
            Me.txtCostCode.SetFocus
        Else
            Response = acDataErrContinue
            Me.cmbTeamName.Undo
        End If
        .SetWarnings True
    End With
End Sub  

在前面的过程中也使用了这个:

Public Sub GoToBookmark(frm As Form, FieldName As String, FieldValue As String)

    Dim rst As DAO.Recordset
    Dim rst_Type As Long

    On Error GoTo ERR_HANDLE

    Set rst = frm.RecordsetClone

    FieldName = "[" & FieldName & "]"

    Select Case rst.Fields(FieldName).Type
        Case 4 'dbLong
            rst.FindFirst FieldName & "=" & FieldValue
        Case 10 'dbText
            rst.FindFirst FieldName & "='" & FieldValue & "'"
    End Select

    If Not (rst.BOF And rst.EOF) Then
        frm.Recordset.Bookmark = rst.Bookmark
    End If

    rst.Close

EXIT_PROC:

        Set rst = Nothing

        On Error GoTo 0
        Exit Sub

ERR_HANDLE:
        'Commented out so I don't have to post the DisplayError procedures.
        'DisplayError Err.Number, Err.Description, "mdl_GoToBookMark.GoToBookmark()"
        Resume EXIT_PROC

End Sub

问题: 当我在组合框中输入新的团队名称时,它会询问我是否要将其添加到团队列表中,然后它会添加团队并将我移动到 CostCode 文本框,如果可用,我可以在其中输入成本代码。 如果成本代码不可用,则控件应保持空白,但当我移动到另一个控件或记录(即控件失去焦点)时,该记录的主键将出现在 CostCode 文本框中,并在我更改记录时保存(失去焦点只是把它放在文本框中,它不会出现在表格中,直到记录被保存)。

【问题讨论】:

时髦的行为。我怀疑在NotInList 事件过程中做所有这些事情对于Access 来说有点太多了。注意Me.Requery 也会触发Form_Current(),所以我想说Me.cmbTeamName 操作都是多余的。您可以将独立的示例数据库上传到文件主机吗? 我很高兴NotInList 事件中没有发生太多事情。这将是一个真正的痛苦来解决。我将再看一下Me.Requery,尽管在GoToBookMark 调用的任一侧使用它似乎有点矫枉过正,即使第二个调用只请求控件。我会让你知道... 乍一看,我确实可以删除第一个重新查询并更改第二个以重新查询整个表单。我必须检查一下它没有损坏其他任何东西,但目前一切看起来都很好。 【参考方案1】:

您的问题在于以下行:

Response = acDataErrAdded

一旦失去焦点,此行将触发 Access 将具有焦点的字段设置为您刚刚添加的值。因为您将焦点转移到不同的领域,所以会出现这种奇怪的行为。

将其更改为 Response = acDataErrContinue(这基本上告诉 Access 不关心您输入的内容,并让您自己处理)并且您的代码应该按预期运行。

【讨论】:

谢谢埃里克。那成功了。我终于可以摆脱最后一个不会真正影响数据库操作的烦人错误(成本代码比 PK 大得多,所以当它是错误的数字时很明显)总是需要学习新东西。跨度>

以上是关于出现在控制源不是 PK 字段的文本框中的记录的主键的主要内容,如果未能解决你的问题,请参考以下文章

使用自动生成的主键 PK 的核心数据

定义属性

19 01 18 dango 模型

Django框架:模型 定义属性

一个表中的主键是不是也可以作为主键出现在另一个表中?

Django查询 – id vs pk