SELECT @@ IDENTITY не ограничен объектом БД? - PullRequest
4 голосов
/ 10 мая 2011

У меня есть следующий код в 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

Я ожидаю, что это выведет следующее (т. Е. Каждый отдельный объект БД будет иметь свое собственное значение "самая последняя идентичность"):

1     2
1     2    0

Вместо этого я получаю (т. Е. Он имеет глобальную область видимости):

1     2
2     2    2

Я думал, что SELECT @@IDENTITY - это безопасный способ получить последний идентификатор автономного номера в Jet 4.0+.Что я делаю неправильно?

Ответы [ 2 ]

7 голосов
/ 10 мая 2011

Оказывается, что SELECT @@IDENTITY ограничено сессией. В ADO это обрабатывается через соединение. В DAO мы должны использовать рабочие пространства, чтобы изолировать область действия. Следующий код работает как положено:

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, но это достаточно просто для кодирования.

0 голосов
/ 10 мая 2011

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

Несмотря на то, что это код .Net, ключом является тот факт, что @@ Identity зависит от соединения, и, поскольку вы используете CurrentDb в обоих случаях, будет использоваться одно и то же соединение..

...