【问题标题】:SELECT @@IDENTITY not scoped by DB object?SELECT @@IDENTITY 不受 DB 对象的限制?
【发布时间】:2011-05-09 21:37:57
【问题描述】:

我在 MS Access 中有以下代码:

Sub IdentityFail()
Dim db1 As DAO.Database, db2 As DAO.Database
Dim id1 As Long, id2 As Long

    CurrentDb.Execute "CREATE TABLE LocalDummy (Col1 AUTOINCREMENT, Col2 INT)", dbFailOnError
    Set db1 = CurrentDb
    Set db2 = CurrentDb
    db1.Execute "INSERT INTO LocalDummy(Col2) VALUES(Null)", dbFailOnError
    id1 = db1.OpenRecordset("SELECT @@IDENTITY")(0)
    db2.Execute "INSERT INTO LocalDummy(Col2) VALUES(Null)", dbFailOnError
    id2 = db2.OpenRecordset("SELECT @@IDENTITY")(0)

    Debug.Print id1, id2
    Debug.Print db1.OpenRecordset("SELECT @@IDENTITY")(0), _
                db2.OpenRecordset("SELECT @@IDENTITY")(0), _
                CurrentDb.OpenRecordset("SELECT @@IDENTITY")(0)
End Sub

我希望这会输出以下内容(即,每个不同的 db 对象都有自己的“最新身份”值):

1     2
1     2    0

相反,我得到了(即,它似乎是全局范围的):

1     2
2     2    2

我认为SELECT @@IDENTITY 是在 Jet 4.0+ 中获取最新自动编号 ID 的安全方法。我究竟做错了什么?

【问题讨论】:

    标签: ms-access jet


    【解决方案1】:

    原来SELECT @@IDENTITY 的范围是会话。在 ADO 中,这是通过连接处理的。在 DAO 中,我们必须使用 Workspaces 来隔离作用域。以下代码按预期工作:

    Sub IdentitySucceed()
    Dim ws1 As DAO.Workspace, ws2 As DAO.Workspace
    Dim db1 As DAO.Database, db2 As DAO.Database
    Dim id1 As Long, id2 As Long, DbPath As String
    
        CurrentDb.Execute "CREATE TABLE LocalDummy (Col1 AUTOINCREMENT, Col2 INT)", dbFailOnError
        'The workspace names need not be unique;'
        '  we'll use the objects themselves (ws1 and ws2) to keep them straight'
        Set ws1 = DAO.CreateWorkspace("TempWS", "Admin", "")
        Set ws2 = DAO.CreateWorkspace("TempWS", "Admin", "")
        DbPath = Application.CurrentProject.Path & "\" & _
                 Application.CurrentProject.Name
        Set db1 = ws1.OpenDatabase(DbPath)
        Set db2 = ws2.OpenDatabase(DbPath)
        db1.Execute "INSERT INTO LocalDummy(Col2) VALUES(Null)", dbFailOnError
        id1 = db1.OpenRecordset("SELECT @@IDENTITY")(0)
        db2.Execute "INSERT INTO LocalDummy(Col2) VALUES(Null)", dbFailOnError
        id2 = db2.OpenRecordset("SELECT @@IDENTITY")(0)
    
        Debug.Print id1, id2
        Debug.Print db1.OpenRecordset("SELECT @@IDENTITY")(0), _
                    db2.OpenRecordset("SELECT @@IDENTITY")(0), _
                    CurrentDb.OpenRecordset("SELECT @@IDENTITY")(0)
    End Sub
    

    这会输出以下内容:

    1    2
    1    2    2
    

    CurrentDb 仍然不会返回 0,但这很容易编写代码。

    【讨论】:

    • 哇,这很有趣。我会猜到它是由实际数据库引起的,并且由于使用 CurrentDB 初始化的数据库变量始终是同一个数据库,因此它们都会返回相同的东西。干得好! +1
    【解决方案2】:

    http://www.mikesdotnetting.com/Article/54/Getting-the-identity-of-the-most-recently-added-record

    虽然它是 .Net 代码,但关键是 @@Identity 是特定于连接的,并且由于您在两种情况下都使用 CurrentDb,因此将使用相同的连接。

    【讨论】:

    • 我没有使用连接。这是从 MS Access 内部运行并在本地表上运行的 DAO 代码。
    • CurrentDB 不是一个连接对象——它是一个指向当前在 Access UI 中打开的数据库的结构。
    猜你喜欢
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 2013-07-05
    • 2010-09-25
    • 2011-05-07
    • 1970-01-01
    • 2020-04-15
    • 1970-01-01
    相关资源
    最近更新 更多