【问题标题】:MS Access Write Conflict - SQL Server - Me = DirtyMS Access 写入冲突 - SQL Server - 我 = 脏
【发布时间】:2022-04-13 03:54:00
【问题描述】:

我收到错误消息:

自从您开始编辑此记录后,其他用户已对其进行了更改。如果您保存记录,您将覆盖其他用户所做的更改...

我知道这是一个常见问题,我花了数小时研究和测试,但无济于事。几点说明:

  1. 我的数据库中没有位域
  2. 所有表都有一个主键,数据类型 = 身份
  3. 所有表在更新和插入时都有创建/修改时间戳触发器

我相当肯定,当表单(和多个子表单)正在创建身份字段和/或时间戳触发器时,一定会出现问题。具体来说,当我返回编辑旧的“鱼”(如屏幕截图所示)时,我只会在“个人鱼”表上收到此错误。如果我只是浏览表单而不进行任何编辑,它工作正常。但是如果我需要在之前的“鱼”上编辑任何东西——在身份/触发器触发之后——那么它会给我错误。

我已经完成并在每个表单中添加了If Me.Dirty Then Me.Dirty = False End If,用于以下事件: On Current, On Load, On Click, After Update, Before Update, Before Insert, On Dirty

我还将DoCmd.RunCommand acCmdSaveRecord 添加到On Deactivate。我承认我不擅长 VBA,所以我在这里做了一些愚蠢的事情。附上代码。我也搞砸了Record Locks = Edited Record

到目前为止,似乎没有任何效果。如果您认为我遗漏了什么,请告诉我。另外,如果您对我的数据库设计或其他方面有任何随机的 cmets 或建议,我随时欢迎反馈。

谢谢!

更新:

Albert 的回答让我找到了正确的地方。简短的版本是向所有表添加一个 rowversion(又名时间戳)字段。这在其他几篇文章中提到过,但我没有意识到[可怕的]“时间戳”实际上与日期或时间无关。感谢您的帮助!

]3

【问题讨论】:

  • 代码和错误信息应该是有问题的格式化文本,而不是图像。
  • “所有表在更新和插入时都有创建/修改时间戳触发器”是什么意思。表上的触发器是巨大的安装珠穆朗玛峰的问题。绝对惊天动地和巨大巨大的巨大问题。更大更糟糕的是,TS 列不是您设置的值,而是服务器端列,应该被 Redmond 的人们称为 rowversion - (时间戳是这种列的世界上最糟糕的名称类型)。这是时间戳类型的内部二进制行版本列,但您确实意识到此类列的时间为零零零零 - 对吧?
  • 那个触发器到底是什么?如果它正在对书面记录进行插入或更新,那就有问题了
  • 每个表都有一个“created_date”、“created_user”、“modified_date”和“modified_user”触发器,在插入(创建和修改)和更新(修改)时运行。我删除了这些表上的所有触发器,现在它可以工作了。感谢那。但是现在我不得不问 - 我知道触发器是一个非常冒险/有争议的主题 - 在不使用触发器的情况下让那些“创建日期”“修改日期”字段的最佳方法是什么?我可以不使用它们吗?或者我可以将触发器留在原处,但有人将它们从表单/ODBC 连接中删除?再次感谢您的帮助!

标签: sql-server ms-access


【解决方案1】:

好的,这里有很多东西要检查。首先,将 me.Dirty = false 置于 on-current 或更新前的事件将导致“相同”事件再次尝试触发。你真的(但真的)不想这样做。 (在这些事件中随意乱扔 me.dirty 只会使这个问题变得更糟,并且经常导致相同的事件再次触发。

接下来:

All tables have a create/modified timestamp trigger on updates and insert

好的,现在上面的内容令人困惑。您是否有实际的触发器 - 因为这是一个单独的问题,并且通常会触发记录被其他人修改。

此外,当我们谈到时间戳列时,请记住,此类列与日期时间有零零零。多年来,微软一直试图“改变”所使用的名称。正确的名称是 ROWVERSION,并且此列不是 datetime 数据类型列,而是称为时间戳。不要以任何方式将此行版本系统/列与日期时间列混淆。

因此,假设是: 您有一个时间戳列 - 这是数据类型的时间戳。您的代码或触发器不会以任何方式触及此列。此列既不是 datetime,也不是 datetime2,而是数据类型 timestamp。

如果您在此处没有实际的时间戳列(它不需要在表单上),那么您将不断收到“脏”警告。您还可以使用任何真实的数据类型列来获得这一点 - 特别是如果它们是由服务器代码设置的。 (访问将四舍五入)。

底线: 您需要该表中的实际行版本列(时间戳类型)。在幕后,如果访问没有找到此列,那么它将逐列进行比较,并且毫无疑问地使用触发器在服务器端触发器上使用 GETDATE() 设置一些 LastUpdated 列,那么这只会导致问题。时间戳列的引入将停止在更新后进行逐列比较的访问,并且它只会查看时间戳列。因此,您的触发器现在可以更新 LastUpdated,并且从访问角度来看,时间戳列不应更改。

所以,你需要确定:

访问看到一个PK列-所有sql表都需要一个PK。

所有表都应该有一个 rowversion 列。

如果您确实在问题表中添加了时间戳 (rowverison) 列,请确保在访问客户端重新链接。事实上,在任何表更改或修改服务器端之后,您应该重新链接客户端。

我会删除任何流浪的 me.Dirty = False 格式的代码。

如果您愿意,可以在表单上放置一个“保存”按钮,然后就可以使用了

if me.dirty = true then me.Dirty = False

编辑

通过上述设置,您应该能够重新引入设置 LastUpdated 的服务器端触发器。但是,您不希望任何“接触”或使用该列的形式的代码。但是,您应该能够将该 LastUpdated 列放入表单中,并在保存后查看它的更新。

【讨论】:

    【解决方案2】:

    底线,因为我在将 SQL Server 升级到 2016 时遇到了这个错误,因为没有假设“时间戳”是数据类型“日期时间”。它不是。 Access 需要的数据类型是“时间戳”类型。将具有该数据类型的列添加到可通过 Access 编辑的任何表中,这将清除“写入冲突并显示灰色保存按钮”消息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-23
      • 2014-09-25
      • 1970-01-01
      • 2010-10-29
      • 2021-07-03
      • 2020-02-10
      相关资源
      最近更新 更多