我可以用事务包装 Access 表单吗?

Posted

技术标签:

【中文标题】我可以用事务包装 Access 表单吗?【英文标题】:Can I wrap an Access form with a transaction? 【发布时间】:2009-07-12 23:02:14 【问题描述】:

我想制作一个基本上创建发票的表单,但使用一些其他相关数据作为输入或限制;在将项目添加到发票的过程中,我需要减少另一个表中的项目。由于用户将一次输入多个项目,我想在表单加载时发出“START TRANSACTION”,然后在表单更新时执行“COMMIT”。因此,如果他们取消表单,其他相关表(通过子表单显示)将回滚到以前的值。

【问题讨论】:

【参考方案1】:

无法使用绑定表单完成。您可以使用临时表来存储数据,然后更新主表。有点笨拙,但我过去做过。

请参阅TempTables.MDB page at my website,它说明了如何在您的应用中使用临时 MDB。

【讨论】:

讨厌,但它似乎是唯一的答案。【参考方案2】:

是的,可以使用以下代码以您需要的形式控制交易:

Private Sub Form_Open(取消为整数) 设置 Me.Recordset = CurrentDb.OpenRecordset("NAME_OF_YOUR_TABLE_OR_QUERY") 结束子

之后,您可以使用 DBEngine 来控制事务。

它对我有用(我使用 Access 2007)

注意:如果您使用表单界面插入新记录,则在引发 Form_AfterInsert 事件时它是可见的,因此您可以在该事件中使用 DbEngine.Rollback 撤消更改。

【讨论】:

将表单的记录集设置为在代码中创建的记录集可能会出现问题。另外,我看不到您的建议是如何工作的,因为您需要使用一个使用默认工作区以外的工作区初始化的数据库对象。我也对像这样直接使用 CurrentDB.OpenRecordset() 持怀疑态度——看起来像是对隐式引用问题或损坏的记录集的公开邀请。【参考方案3】:

我发现它可以在绑定表单上使用。在任何父控件的更改事件中分配包含 ID 号的变量所需的一切。比您需要将该 ID 值传输到子表单连接字段并在主表单和子表单上执行事务。这是我如何做到的示例。

Primary Form VBA

Option Compare Database
Option Explicit

Private boolFrmDirty As Boolean
Private boolFrmSaved As Boolean

Private Sub EmpolyeesID_Change()
Dim ordID As Integer
Dim subFormOrdID As Object

Set subFormOrdID = Forms!Order.OrderInstallation.Form!OrderID

ordID = Me.Form!OrderID

subFormOrdID.DefaultValue = ordID

End Sub

Private Sub Form_AfterDelConfirm(Status As Integer)
    If Me.Saved = False Then Me.Saved = (Status = acDeleteOK)
End Sub
Private Sub Form_AfterUpdate()
    Me.Saved = True
End Sub
Private Sub Form_Delete(Cancel As Integer)
    If Me.Dirtied = False Then DBEngine.BeginTrans
    Me.Dirtied = True
End Sub
'Check if form has got new values in it
Private Sub Form_Dirty(Cancel As Integer)
    If Me.Dirtied = False Then DBEngine.BeginTrans
    Me.Dirtied = True
End Sub
'Open Form as a Record Set and set the variables for it
Private Sub Form_Open(Cancel As Integer)
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Set db = CurrentDb
    Set rs = db.OpenRecordset("SELECT * FROM Orders", dbOpenDynaset, dbAppendOnly)
    Set Me.Recordset = rs
End Sub
Private Sub Form_Unload(Cancel As Integer)
    Dim msg As Integer
    If Me.Saved Then
        msg = MsgBox("Do you want to commit all changes?", vbYesNoCancel)
        Select Case msg
            Case vbYes
                DBEngine.CommitTrans
            Case vbNo
                DBEngine.Rollback
            Case vbCancel
                Cancel = True
        End Select
    Else
        If Me.Dirtied Then DBEngine.Rollback
    End If
End Sub

Public Property Get Dirtied() As Boolean
    Dirtied = boolFrmDirty
End Property

Public Property Let Dirtied(boolFrmDirtyIn As Boolean)
    boolFrmDirty = boolFrmDirtyIn
End Property

Public Property Get Saved() As Boolean
    Saved = boolFrmSaved
End Property

Public Property Let Saved(boolFrmSavedIn As Boolean)
    boolFrmSaved = boolFrmSavedIn
End Property

Private Sub ProductID_AfterUpdate()
'Calculations of VAT and Floor Price
Dim clcVAT As Integer
Dim sqlQry As String
Dim instID As Integer

instID = Me.Form!ProductID.Value

sqlQry = "SELECT Products.Price FROM Products WHERE Products.ProductID =" & instID & ""

Me.flPrice.RowSource = sqlQry

End Sub

Sub Form VBA 

Option Compare Database
Option Explicit
'Transaction for sub-form
Private Sub Form_Open(Cancel As Integer)
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Set db = CurrentDb
    Set rs = db.OpenRecordset("SELECT * FROM OrderInstallation")
    Set Me.Recordset = rs
End Sub
Private Sub Form_AfterUpdate()
    Dim emplID As Object
    Dim cstmID As Object
    Dim prdcID As Object
    Dim DataArray As Variant
    Dim RqrdFieldErorr As String
    Dim qry As String

    Set emplID = Me.Parent!EmpolyeesID
    Set cstmID = Me.Parent!CustomerID
    Set prdcID = Me.Parent!ProductID

    If IsNull(emplID.Value) Or IsNull(cstmID.Value) Or IsNull(prdcID.Value) Then
        MsgBox ("Please enter select required fields first")

        Else
    End If
End Sub
'Restrict updates of Installation subform if Employee, Customer and Product is not selected
Private Sub InstallationID_AfterUpdate()
    Dim instID As Integer
    Dim instPrice As Integer
    Dim strQry As String

    ' Create query based on InstallationID value
    instID = InstallationID.Value
    strQry = "SELECT Installation.Price, Installation.InstallationID FROM Installation WHERE Installation.InstallationID =" & instID & ""
    Me.Price.RowSource = strQry
End Sub

【讨论】:

以上是关于我可以用事务包装 Access 表单吗?的主要内容,如果未能解决你的问题,请参考以下文章

Access 2007 表单错误:您尝试提交或回滚事务

可以通过 VBA 更改 MS Access 子表单字段吗?

Acces数据库注入|偏移注入

MS Access 2010 上的可编辑文本框 - 行为正确吗?

在 MS Access 中使用子表单会降低性能吗?

我可以要求 Postgresql 忽略事务中的错误吗