【问题标题】:"The data has been changed" error when stepping from main form into sub form从主窗体进入子窗体时出现“数据已更改”错误
【发布时间】:2013-04-19 12:43:32
【问题描述】:

我正在使用 SQL Server 迁移助手 (SSMA) 将 Access 数据库迁移到 SQL Server。 Access 应用程序将继续使用,但使用链接表而不是本地表。

我在迁移后测试期间遇到了一个问题,其中包含多个子表单。

测试步骤:

1) 编辑主窗体中的字段;

2) 将焦点转移到子表单中的某个字段;

3) 尝试编辑子表单中的字段。

结果:弹出错误消息:“数据已更改。另一个用户编辑了此记录并在您尝试保存更改之前保存了更改。”

一旦错误消息消失,子表单中的字段就可以被编辑。如果主表单中的字段未编辑,则可以编辑子表单而不会出现错误消息。

关于可能导致此错误的任何想法?

我已经尝试在主窗体上的子窗体控件的 Enter 事件处理程序中保存主窗体记录(即,当进入包含子窗体的控件时,此事件发生在主窗体上,而不是在子窗体上形式本身)。没有任何区别。我尝试在同一个子表单控件 Enter 事件中重新查询主表单,但这不起作用 - 重新查询主表单会将焦点从子表单移开,因此无法对其进行编辑。

MS 论坛在子表单的 After_Update 事件中建议 Me.Parent.Requery。那也没用。

当我进入子表单时,SQL Profiler 显示了一个更新语句,更新主表单下的表。没有其他语句访问数据库来修改数据。

我注意到一件有趣的事情:主窗体的记录源实际上是一个将两个表连接在一起的选择语句。主窗体包含可以更新记录源中每个表中的列的字段。在主窗体中编辑更新关系中的子表的字段不会导致“数据已更改”错误。该错误仅在编辑更新关系中的父表的字段时发生。我已经尝试过更新两个表中不同列的字段。结果一致:在父表中编辑记录会导致错误,在子表中编辑记录不会。

子表单和主表单之间的链接将子表单表中的列连接到主表单记录源中子表中的列。

顺便说一下,主窗体Record Source中的表实际上是以1:1的关系连接的(子表中的一条记录与父表中的每条记录)。子表只是父表的扩展表。

如果我从头开始,我个人不会设计这样的系统,但这是我必须使用的,我希望有一些相当简单的修复,不需要对系统进行重大重新设计表格或表格(假设主表格和子表格各有 100 多个控件)。

【问题讨论】:

  • 您是否尝试在 SQL Server 上创建一个视图,该视图返回与主窗体的当前记录源相同的列,将该视图链接为 Access 中的“链接表”,然后使用 作为主窗体的记录源?
  • 1:1 关系对我来说似乎很可疑,因为您收到的错误反映了最有可能由 ODBC 发出的并发用户故障。也许您可以尝试删除 1:1 关系,看看是否可以隔离错误。
  • @Gord Thompson:试过了,使用一个替代触发器来处理视图的更新。发现我必须在 Access 端向链接表添加唯一索引以允许记录可更新。表单的工作方式与最初的完全相同,当我更新映射到一个 SQL Server 表的字段时出现错误对话框,但当我更新映射到另一个表的字段时没有问题。当我关闭错误对话框时,我可以像以前一样更新映射到问题表的字段。所以现在我怀疑这一定与各个表单控件的属性有关。

标签: ms-access vba odbc ms-access-2007


【解决方案1】:

经过反复试验,我解决了这个问题。在主窗体上的子窗体控件的 enter 事件处理程序中,我请求了子窗体本身。

例如在主窗体上:

Private Sub Subform1_Enter()
    Me.Subform1.Form.Requery
End Sub

我不知道为什么会这样,只是它确实有效。

【讨论】:

  • 我遇到了相反的问题:从子表单转到主表单时出现错误。所以在Subform1_Exit() 事件中我输入了Me.Requery 并且它起作用了。
【解决方案2】:

当更新表中的记录时会发生这种情况,但主窗体的记录源尚未刷新以反映更改,因此 Access 获取冲突信息并认为记录已更改。另见:http://support.microsoft.com/kb/302492

【讨论】:

  • 阅读那篇支持文章,我似乎遇到了几乎相反的问题:我先编辑了主表单,然后再进入子表单。我怀疑我可以修改那篇文章的答案来解决我的问题:在主窗体中控件的 AfterUpdate 事件处理程序中,我可以添加 Me.Subform1.Form.Requery。我还没有尝试过,但我怀疑它会起作用以及将该行添加到主窗体上的子窗体 Enter 事件中(这是我为解决问题所做的)。
【解决方案3】:

我通过像这样编写 AfterUpdate 表单事件来解决这个问题:

Private Sub Form_BeforeUpdate(Cancel As Integer)
    cSQL = "update UnderlinedTable set Field1=" & Me.Controls("Field1") & _
        ", Field2=" & Me.Controls("Field2") & _ ' and all other fields in your form
        " where PrimaryKey=" & Me.Recordset.Fields("PrimaryKeyField")
    ' here command to SQL server that executes this cSQL string
    Me.Requery
    Cancel = True 'stop Access updating
end sub

可以编写通用的 BeforeUpdate 表单事件函数,该函数根据 form.recordsource 和更改的表单字段自动生成更新语句,这些表单字段可以从所有 AfterUpdate 表单事件中调用,并将表单作为参数传递。这是我为我做的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多