Je migre une application Access classique vers Sql Server, c'est-à-dire des tables DAO + liées.Transactions utilisant des tables liées DAO et Sql Server
J'ai trouvé un comportement fustrant: lorsque j'apporte des modifications en utilisant des jeux d'enregistrements sur des tables liées, Access utilise plusieurs connexions. Plus d'une connexion signifie plus d'une transaction à la fois sur le serveur. Ces transactions sont indépendantes. Pas imbriqué
Le comportement standard d'accès MS utilisant des tables liées à un fichier .mdb est différent. Il n'y a qu'une seule transaction à la fois. Chaque changement de base de données est visible par tout code qui s'exécute dans le même DAO.Workspace avant d'exécuter la validation.
Les règles ont été modifiées et le code DAO existant utilisant les transactions côté client échouera. Si j'ajoute ou met à jour un enregistrement en utilisant un jeu d'enregistrements ouvert comme dbOpenDynaset, tout code essayant de les lire après échouera: Ne trouve pas de nouveaux enregistrements et voit les enregistrements existants dans leur état d'origine. Pourquoi? Étant donné que les opérations sont exécutées dans plusieurs transactions indépendantes
En exécutant l'exemple de code fourni, sql profiler vous montre que différentes opérations sont effectuées avec différents ID de transaction.
J'ai testé cela en utilisant ADO et tout fonctionne bien. Mais il y a des milliers de lignes de code.
Existe-t-il une solution autre que le code de réécriture utilisant ADO?
Puis-je modifier le comportement standard d'accès? (lire le niveau d'isolement non-validé, indiquer de ne pas ouvrir de nouvelles connexions, ...)
Le code ci-dessous reproduit le problème. Il est très simple:
Ouvrir une 1.- sur recordset existant enregistrement
Ajouter un nouvel enregistrement 2.-
Essayez de lire 3.- enregistrer
récemment ajouté Si j'utilise dans dbOpenDynaset (1), i ne verra pas de nouveau record dans (3).
J'utilise Acc-2010, les fichiers de format .accdb et Sql Server 2008 R2
Merci.
Private Sub test0()
Dim bResult As Boolean
Dim bUseTrans As Boolean 'New record added in transaction
Dim rsExist As DAO.Recordset2 'Dummy recordset
Dim tRecordsetExist As DAO.RecordsetTypeEnum 'Dummy recordset type:
' with dbOpenDynaset fail.
' Any other works fine
Dim rs2Add As DAO.Recordset
Dim rs2Read As DAO.Recordset 'Used to read recently added record
Dim tRecordset2Read As DAO.RecordsetTypeEnum 'Recordset type used to read new record. Doesn't affect
Dim bTranInitiated As Boolean 'Track if we are in transaction
Dim lngExistingNumber As Long
Dim lngNewNumber As Long
Dim lngNewID As Long
Dim strSQL As String
On Error GoTo HandleErr
'Invoices table definition in SS. Table is linked as [dbo_Invoices]:
' CREATE TABLE [dbo].[Invoices](
' [IdInvoice] [int] IDENTITY(1,1) NOT NULL,
' [InvoiceNumber] [int] NOT NULL,
' [InvoiceDescription] [varchar](50) NOT NULL,
' CONSTRAINT [PK_Invoices] PRIMARY KEY CLUSTERED
' (
' [IdInvoice] Asc
' )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
' ) ON [PRIMARY]
Set wks = DBEngine.Workspaces(0)
Set dbs = wks.Databases(0)
bUseTrans = True 'Without transaction everything works well
tRecordsetExist = dbOpenDynaset 'Dummy recordset type:
' dbOpenDynaset makes fail.
' Any other works fine
tRecordset2Read = dbOpenForwardOnly 'Does not affect
lngExistingNumber = 12001
lngNewNumber = -lngExistingNumber
'Clean previous runs of the test and make sure that referenced invoice exists.
dbs.Execute "Delete from dbo_Invoices Where InvoiceNumber = " & lngNewNumber, dbFailOnError Or dbSeeChanges
On Error Resume Next
strSQL = "Insert Into dbo_Invoices (InvoiceNumber, InvoiceDescription) " & _
" Values (" & lngExistingNumber & ", 'Original invoice')"
dbs.Execute strSQL, dbFailOnError Or dbSeeChanges
On Error GoTo HandleErr
If bUseTrans Then
wks.BeginTrans
bTranInitiated = True
End If
strSQL = "Select IdInvoice, InvoiceNumber from dbo_Invoices " & _
" Where InvoiceNumber = " & lngExistingNumber
If tRecordsetExist = dbOpenDynaset Then
Set rsExist = dbs.OpenRecordset(strSQL, dbOpenDynaset, dbSeeChanges)
Else
Set rsExist = dbs.OpenRecordset(strSQL, tRecordsetExist)
End If
If rsExist.BOF And rsExist.EOF Then
Err.Raise vbObjectError, , "Original invoice " & lngExistingNumber & " not found"
End If
Set rs2Add = dbs.OpenRecordset("Select * from dbo_Invoices", dbOpenDynaset, dbAppendOnly Or dbSeeChanges)
rs2Add.AddNew
rs2Add!InvoiceNumber = lngNewNumber
rs2Add!InvoiceDescription = "Invoice anulation, ref " & lngExistingNumber
rs2Add.Update
'After executing .Update rs2Add goes to .EOF. This action reposition the recordset on the new record
rs2Add.Move 0, rs2Add.LastModified
lngNewID = rs2Add!IdInvoice
Debug.Print "New record added: IdInvoice = " & rs2Add!IdInvoice & ", InvoiceNumber = " & rs2Add!InvoiceNumber
'Try to read the new record
strSQL = "Select * from dbo_Invoices Where IdInvoice = " & lngNewID
If tRecordset2Read = dbOpenDynaset Then
Set rs2Read = dbs.OpenRecordset(strSQL, dbOpenDynaset, dbSeeChanges)
Else
Set rs2Read = dbs.OpenRecordset(strSQL, tRecordset2Read)
End If
If (rs2Read.BOF And rs2Read.EOF) Then
Err.Raise vbObjectError, , "rs2Read: Not found using IdInvoice = " & lngNewID
End If
Debug.Print "New record found with IdInvoice = " & rs2Read!IdInvoice
rs2Read.Close
bResult = True
ExitHere:
If Not wks Is Nothing Then
If bTranInitiated Then
If bResult Then
wks.CommitTrans
Else
wks.Rollback
End If
bTranInitiated = False
End If
End If
On Error Resume Next
If Not rs2Add Is Nothing Then
rs2Add.Close
Set rs2Add = Nothing
End If
If Not rs2Read Is Nothing Then
rs2Read.Close
Set rs2Read = Nothing
End If
Exit Sub
HandleErr:
Dim e As Object
If Err.Description Like "ODBC*" Then
For Each e In DBEngine.Errors
MsgBox e.Description, vbCritical
Next
Else
MsgBox Err.Description, vbCritical
End If
bResult = False
Resume ExitHere
Resume
End Sub
Merci. Mais j'ai abandonné. Nous avons décidé de réécrire. Le "IsolateODBCTrans" ne résout pas. Je ne veux pas plus d'une transaction, juste oine. Je ne veux pas plus d'une connexion. – ricardohzsz
C'est aussi ce que j'ai pensé du problème. Pitié. Au moins vous obtenez un changement pour optimiser le code un peu ;-) – milivojeviCH
Comme vous êtes le seul qui a essayé d'offrir une solution à ce problème, j'ai décidé de vous récompenser avec la prime;) Peut-être que c'est un problème sans solution. Merci quand même. – Jonathan