将Excel中的单元格复制/粘贴到Access子窗体中时,如果没有创建父记录,则会导致错误 - 正如预期的那样。
问题在于,在发生此错误后,访问将被锁定在这样一种状态:输入的所有后续数据都会导致 操作不支持 错误。当您打开表格时,您可以看到新添加的数据尚未出现在表格中 - 因此看起来好像Access实际上正在进行某种交易。
我试过点击'保存' ..'刷新' ..甚至添加一个AfterInsert事件来强制commitTrans()但没有运气 - 并且Access声称没有正在进行的事务
如果手动输入记录,则没有错误。粘贴记录时似乎只会出现问题。我猜测Access正在创建一个事务来处理多个记录操作,并且没有正确地从错误中恢复。
我可以删除“必需”'标志,它会工作 - 但你有孤儿记录。我想也许可以使用After Insert Data Macro添加一个带有默认批处理名称的新批处理,并将新的BatchID自动填充到Items表中。我不确定如何做到这一点。
我确实尝试删除了“必需”'使用更改前数据宏来标记和捕获错误 - 虽然它减少了错误 - 它仍然产生相同的事务中不支持的操作错误。
我查找了Microsoft知识库中的错误,但没有找到任何特定于我的情况。我在stackoverflow中搜索了错误消息但没有找到任何内容。
我创建了一个新数据库,并且能够复制该问题。
复制步骤
设置数据库
正如您所看到的,手动工作正常。
从Excel复制和粘贴数据
此时 - 您应该看到输入的BatchID,批次名称和新数据。所有出现都按预期工作。如果您尝试刷新或导航到另一个批记录 - 您将收到错误 交易中不支持的操作 。 Access将继续显示此错误消息,直到我们关闭并重新打开表单。您粘贴的数据不会进入数据库。
通常情况下,具有一点技术知识的人会意识到某些事情并不顺利并且从数据库中关闭并重新打开...但不幸的是,我有玩耍的用户"打击鼹鼠& #34;使用任何弹出框然后尝试继续 - 所以我想尽可能地防范。
所需解决方案
我想解决问题的方法,最终导致其他带有访问权限,重复值等的怪癖。
根据我自己的经验,使用VBA来修复&#39;钥匙不可靠。数据宏似乎更可靠 - 但它们设置起来可能很棘手 - 它们还不是主流(我说应该有一个 ms-access-data-macros < / em>标签在stackoverflow上,但还没有)
答案 0 :(得分:1)
建议的解决方法:
在[批次]表格中,将[BatchName]字段的Required
属性设置为Yes
。
将[BatchID]文本框的Tab Stop
属性更改为“否”。这将在表单打开时为[BatchName]文本框提供默认焦点。
让表单的On Current
事件为[BatchName]文本框指定新记录的焦点(IsNull(Me.BatchID) = True
)。
当[BatchName]文本框失去焦点时,使表单变脏。
Option Compare Database
Option Explicit
Dim DeletePending As Boolean
Private Sub Form_Load()
DeletePending = False
Me.ItemSubForm.Enabled = False ' Disable Subform by default
End Sub
Private Sub Form_Current()
If IsNull(Me.BatchID) Then
Me.BatchName.SetFocus
' Disable Subform if BatchID is NULL
Me.ItemSubForm.Enabled = False
Else
' Enable SubForm Otherwise
Me.ItemSubForm.Enabled = False
End If
End Sub
Private Sub Form_BeforeDelConfirm(Cancel As Integer, Response As Integer)
DeletePending = True
End Sub
Private Sub Form_AfterDelConfirm(Status As Integer)
DeletePending = False
End Sub
Private Sub BatchName_LostFocus()
If IsNull(Me.BatchID) And Not DeletePending Then
Me.Dirty = True
End If
End Sub
当用户单击子窗体(并关闭[BatchName]文本框)时,它们会使窗体变脏并且BatchID获取值。然后他们可以粘贴,并且他们没有收到[BatchID]的“你必须输入值...”消息。如果他们没有输入[BatchName]值,他们现在会被提示输入 it (因为它现在是Required
),但至少他们可以从中优雅地恢复。
更新时间2013-11-09 18:40 UTC:
在玩这个时,我发现了两个怪癖:
如果您删除了最后一个父记录,Access会执行此操作,然后立即在其位置创建另一个新记录。
如果您导航到“新”父记录然后立即退出(例如,通过 PageDown 和 PageUp 键)Access将创建一个新的记录,然后将表格弄脏,留在该记录上。点击 Esc ,然后移开“新”记录就可以了,它没有造成任何错误,但它肯定会让用户感到困惑。
我已经更新了答案,试图解决这些问题。我添加了一些VBA代码来跟踪“DeletePending”状态。我还添加了[BatchName]在[Batches]表中设置为Required = Yes
的要求。如果用户进入“新”记录然后立即再次退出,后者会使其更直观(虽然稍微有些烦人)。
答案 1 :(得分:1)
我知道这是一个古老的故事,我也对此感到不安。 我的解决方案是重新设置该过程,以便用户关闭接收数据的表单以保存插入的记录。既不优雅又高效,使我无法猜测可能发生的每一件事。
答案 2 :(得分:0)
避免不受欢迎的内部交易就足够了 使用以下代码编写子表单错误事件:
Private Sub Form_Error(DataErr As Integer, Response As Integer)
Response = acDataErrContinue
End Sub
拦截子表格事件的一般方法是
' parent form code
' ---------------------------------------------------
Private WithEvents subFormObj As [Form_Sottomaschera items]
Private Sub Form_Open(Cancel As Integer)
Set subFormObj = Me.Sottomaschera_items.Form
End Subcode here
' asynchronous way
Private Sub subFormObj_isInserting()
Me.batchName = vbNullString ' this resolves the new ID issue
End Sub
' synchronous way
Public Sub subFormInserting()
Me.batchName = vbNullString
End Sub
' sub-form code
' ---------------------------------------------------
Public Event isInserting() ' for asynchronous way
Dim parentFormObj As Form_Maschera1 ' for synchronous way
Private Sub Form_BeforeInsert(Cancel As Integer)
parentFormObj.subFormInserting
RaiseEvent isInserting
' Cancel = True
End Sub
Private Sub Form_Error(DataErr As Integer, Response As Integer)
Response = acDataErrContinue
End Sub
Private Sub Form_Open(Cancel As Integer)
Set parentFormObj = Me.Parent
End Sub
其中[Maschera1]
是主要表单,[Sottomaschera items]
是子表单。
不幸的是,它无法解决粘贴问题。
要明确解决问题,您需要保存父记录+ SetFocus
技巧,无论是同步还是异步:
Private Sub subFormObj_isInserting()
Me.batchName = vbNullString
DoCmd.RunCommand acCmdSaveRecord
' DoEvents
Me.batchName.SetFocus
End Sub
Public Sub subFormInserting()
Me.batchName = vbNullString
DoCmd.RunCommand acCmdSaveRecord
' DoEvents
Me.batchName.SetFocus
End Sub
答案 3 :(得分:0)
我挣扎了这么久,直到我终于明白发生了什么导致这个错误。需要一篇相当长的文章才能详细介绍细节而不是博客回复来解释这一切。如果有人有兴趣,他们可以留下联系方式,我会联系他们并详细解释。 但是,对于那些想要解决这个问题的人,我可以通过向您提供问题背后的理念来节省大量时间: 在绑定子表单中执行数据事务时,不能引用其他对象。事务处理的内部代码不允许这样做。例如,如果Form_BeforeUpdate事件中的代码在子表单数据事务中尝试打开另一个表单,则会出现错误3246.您可以拥有创建变量,设置值,引用子代码的代码表单控件等,但你不能出去另一个对象。 如果你考虑一下,这是有道理的。谁知道用户或代码进入另一个表单或对象后可能会做什么。它可能永远不会回来或涉及其他让事务悬空的错误。这就是交易必须先完成的原因。 这意味着您必须捕获并解除当用户在事务中尝试单击子表单外部区域时导致的错误2115。这通常发生在大型复制和粘贴期间,其中用户变为住院病人或者在仍然处于子窗体事务中时开始前进到另一个记录。
答案 4 :(得分:0)
我不明白你到底想要什么,所以这个答案可能不够充分。 你可以
.Visible = False
时设置您的子表单属性Me.NewRecord = True
,以防止向其中输入数据.Dirty = False
,添加批名称后,将主表单强制保存到表中。它还允许避免在将一些记录添加到某些数据库中的主窗体之后不将子窗体的记录保存到表中,至少使用动态子窗体.Recordsource。.Visible = True
下面的代码适用于表单视图,也许应该以某种方式扩展(开发)其他视图。
将子窗体Child和您要隐藏/显示的所有其他控件设置为。&#34; a&#34;。
Private Sub Form_Current()
If Me.CurrentView = 1 Then
If Me.NewRecord = True Then
ShowControls False
ElseIf Me![Items subform Child].Visible = False Then
ShowControls True
End If
End If
End Sub
Private Sub BatchName_Text_AfterUpdate()
Dim NewRecordx As Boolean
If Me![Items subform Child].Visible = False And Me.CurrentView = 1 Then ShowControls True
NewRecordx = Me.NewRecord
If Me.Dirty Then Me.Dirty = False 'save the new record to the table
If Me.CurrentView = 1 And NewRecordx Then Me![Items subform Child].Form.Requery
End Sub
Private Sub ShowControls(bVisible As Boolean)
Dim ctl As Control
For Each ctl In Me.Controls
If ctl.Tag = "a" Then ctl.Visible = bVisible
Next ctl
End Sub