子表单不更新动态添加的新数据

Subform doesn't update with new data added on the fly

如果在表单打开时添加数据(通过追加查询),我很难让子表单显示最新数据。

与问题相关的 tables/forms/VBA & SQL 的快速解释:
我有三个 table 记录我部门内的团队、团队中可用的工作角色以及每个角色可用的职位总数。

table 是:

表格如下,TeamID linking Master/Child 字段:

主窗体的 RecordSourceTeams table.
子表单的 RecordSource 是一个查询,它允许用户在 RoleCount 字段中为每个团队中的每个角色输入所需的数字:

SELECT    Team_Composition.TeamID
        , Roles.RoleDesc
        , Roles.Abbrev
        , Team_Composition.RoleCount
FROM    Team_Composition INNER JOIN Roles ON Team_Composition.RoleID = Roles.RoleID
WHERE   Team_Composition.TeamID=[Forms]![Edit_Teams]![cmbTeamName]

主窗体上的团队名称组合框从团队 table 获取数据,并添加 < 新团队 > 作为列表中的第一项(SingleRecord table 就是 - 具有 1 个字段和 1 个记录的 table,因此 SELECT 将起作用):

SELECT DISTINCT     0 AS TeamID
                    , '<New Team>' AS TeamName 
FROM                SingleRecord  

UNION ALL SELECT    TeamID
                    , TeamName 
FROM                Teams 
ORDER BY            TeamName

当打开表单时所有内容都已存在时,这一切都非常有效。我可以更改组合框中的值,然后触发 VBA 代码以移动到该记录并在子窗体中显示 linked 数据。然后我可以添加每个团队的总数。

移动到正确记录的代码如下:

'----------------------------------------------------------------------------------
' Procedure : cmbTeamName_AfterUpdate
' Author    : Darren Bartrup-Cook
' Date      : 12/06/2017
' Purpose   : Keeps the details on the form in sync with the team selected in the combo box.
'             Ensures all teams have all roles available to them by updating the team_composition
'             table with new roles whenever the team is selected.
'-----------------------------------------------------------------------------------
Private Sub cmbTeamName_AfterUpdate()

    'The first item in cmbTeamName is <New Team> which will not exist in the recordset.
    'To avoid FindFirst going to the wrong record an attempt is made to create a new record
    'allowing the form to filter to a non-existant record.
    If cmbTeamName = 0 Then
        DoCmd.GoToRecord , , acNewRec
    Else
        Dim rs As DAO.Recordset
        Set rs = Me.RecordsetClone
        rs.FindFirst "[TeamID]=" & cmbTeamName
        If Not (rs.BOF And rs.EOF) Then
            Me.Recordset.Bookmark = rs.Bookmark
        End If
        rs.Close
        Set rs = Nothing

        If cmbTeamName <> 0 Then
            Update_TeamComposition cmbTeamName.Column(1)
        End If

    End If

End Sub

Update_TeamComposition 过程执行 SQL 语句以确保团队拥有最新的可用角色列表:

Private Sub Update_TeamComposition(TeamName As String)

    With DoCmd
        .SetWarnings False
        .RunSQL "INSERT INTO Team_Composition(TeamID, RoleID) " & _
                     "SELECT TeamID, RoleID " & _
                     "FROM Teams, Roles " & _
                     "WHERE TeamID = (SELECT TeamID FROM Teams WHERE TeamName='" & TeamName & "')"
        .SetWarnings True
    End With

End Sub

现在是问题代码(或者至少是我认为问题所在的地方):
当一个新团队被添加到组合框时,它被插入到 Teams table 并且各种角色也被添加到 Team_Compositiontable。这有效 - 我可以打开 table 并查看其中的记录,但子表单拒绝更新和显示新记录。数据库 ID 显示 1。表单底部的记录计数显示记录 1 of 6,即使这是我添加的第 7 条记录 - Teams table 显示 7 条记录, Team_Composition table 显示角色已添加到团队 ID 7。

添加新队伍的VBA如下:

Private Sub cmbTeamName_NotInList(NewData As String, Response As Integer)
    With DoCmd
        .SetWarnings False
        If cmbTeamName.OldValue = 0 Then
            'A new team needs adding to the Team table.
            .RunSQL "INSERT INTO Teams(TeamName) VALUES ('" & NewData & "')"
            Response = acDataErrAdded
            'The job roles for the team are inserted.
            Update_TeamComposition NewData
        Else
            .RunSQL "UPDATE Teams SET TeamName = '" & NewData & "'" & _
                    "WHERE TeamID = " & cmbTeamName.Column(0)
            Response = acDataErrAdded
        End If
        .SetWarnings True
    End With
End Sub

我尝试在 Else 语句之前添加代码来刷新表单 - Me.RefreshMe.RequeryMe.Repaint

Me.RequeryMe.Refresh 导致 NotInList 代码多次 运行 并最终给出 run-time 2237 - The text you entered isn't an item in the list(在 Me. 行)。 Me.Repaint 似乎什么也没做。

我想我已经包含了所有内容 - 有谁知道在添加新团队时如何让子表单填充角色?在我看来,table 索引似乎没有更新,并且表单无法识别已创建的新记录。

编辑:
在 @June7 的建议下,我将 NotInList 代码更新为:

Private Sub cmbTeamName_NotInList(NewData As String, Response As Integer)
    With DoCmd
        .SetWarnings False
        If Me.cmbTeamName.OldValue = 0 Then
            'A new team needs adding to the Team table.
            .RunSQL "INSERT INTO Teams(TeamName) VALUES ('" & NewData & "')"
            Response = acDataErrAdded
            'The job roles for the team are inserted.
            Update_TeamComposition NewData

            'To stop the Requery from making NotInList fire multiple times
            'the combo box is moved to a team that does exist before the requery.
            'Then it can move to the new record.
            Me.cmbTeamName = Me.cmbTeamName.ItemData(0)
            Me.Requery

            Dim rs As DAO.Recordset
            Set rs = Me.RecordsetClone
            rs.FindFirst "[TeamName]='" & NewData & "'"
            Me.Recordset.Bookmark = rs.Bookmark
            rs.Close
            Set rs = Nothing

            Me.cmbTeamName.Requery
            Me.cmbTeamName = CLng(Me.txtTeamID)

        Else
            .RunSQL "UPDATE Teams SET TeamName = '" & NewData & "'" & _
                    "WHERE TeamID = " & Me.cmbTeamName.OldValue
            Response = acDataErrAdded
        End If
        .SetWarnings True
    End With
End Sub

我还更新了子表单的 SQL,删除了 WHERE 子句,允许表单使用 Master/Child link.

如果不利用 form/subform 的 Master/Child 链接,为什么要绑定主窗体?子窗体 RecordSource 具有引用组合框的筛选条件。那么,如果组合框的 TeamID 为 0,则不存在关联的 Team_Composition 记录。建议您使用子表单容器的 Master/Child 链接属性,而不是查询中的动态过滤器参数。我从不使用动态参数化查询。

将新记录添加到两个 table 后,重新查询主窗体(同时也应该重新查询子窗体)。但是,由于重新查询集中在第一条记录上,还需要移动到刚刚在主窗体上创建的记录(如果按 TeamID 排序,则在最后)或将排序顺序设置为 TeamID DESCENDING 或使用 RecordsetClone 和 Bookmark 代码。

可以在没有 SingleRecord 的组合框 RowSource UNION 查询中创建 行 table。

SELECT 0 As TeamID, "<New Team>" AS TeamName FROM Teams
UNION SELECT TeamID, TeamName FROM Teams ORDER BY TeamName;

如果源 table 没有记录(如首次部署数据库时),组合框列表将为空。解决方法是使用另一个保证有记录的 table(系统 table 可以工作,我使用 MSysObjects)作为虚拟项的来源。

SELECT 0 As TeamID, "<New Team>" AS TeamName FROM MSysObjects
UNION SELECT TeamID, TeamName FROM Teams ORDER BY TeamName;