2009-07-02 5 views
0

Je développe une application dans Access 2007. Elle utilise un frontal .accdb se connectant à un backend SQL Server 2005. J'utilise des formulaires liés aux jeux d'enregistrements ADO lors de l'exécution. Par souci d'efficacité, les enregistrements contiennent généralement un seul enregistrement, et sont interrogés sur le serveur:Les formulaires liés aux jeux d'enregistrements ADO pouvant être mis à jour ne peuvent pas être mis à jour lorsque la source inclut un JOIN

Public Sub SetUpFormRecordset(cn As ADODB.Connection, rstIn As ADODB.Recordset,  rstSource As String) 
Dim cmd As ADODB.Command 
Dim I As Long 

Set cmd = New ADODB.Command 

cn.Errors.Clear 

' Recordsets based on command object Execute method are Read Only! 

With cmd 
    Set .ActiveConnection = cn 
    .CommandType = adCmdText 
    .CommandText = rstSource 
End With 

With rstIn 
    .CursorType = adOpenKeyset 
    .LockType = adLockPessimistic       'Check the locktype after opening; optimistic locking is worthless on a bound 
End With             ' form, and ADO might open optimistically without firing an error! 

rstIn.Open cmd, , adOpenKeyset, adLockPessimistic   'This should run the query on the server and return an updatable recordset 

With cn 
    If .Errors.Count <> 0 Then 
     For Each errADO In .Errors 
      Call HandleADOErrors(.Errors(I)) 
      I = I + 1 
     Next errADO 
    End If 
End With 
End Sub 

rstSource (la chaîne containg la TSQL sur laquelle le recordset est basé) est assemblé par la routine d'appel, dans ce cas de l'événement Open du formulaire étant lié:

Private Sub Form_Open(Cancel As Integer) 
Dim rst As ADODB.Recordset 
Dim strSource As String, DefaultSource as String 
Dim lngID As Long 

lngID = Forms!MyParent.CurrentID 

strSource = "SELECT TOP (100) PERCENT dbo.Customers.CustomerID, dbo.Customers.LegacyID, dbo.Customers.Active, dbo.Customers.TypeID, dbo.Customers.Category, " & _ 
"dbo.Customers.Source, dbo.Customers.CustomerName, dbo.Customers.CustAddrID, dbo.Customers.Email, dbo.Customers.TaxExempt, dbo.Customers.SalesTaxCode, " & _ 
"dbo.Customers.SalesTax2Code, dbo.Customers.CreditLimit, dbo.Customers.CreationDate, dbo.Customers.FirstOrder, dbo.Customers.LastOrder, " & _ 
"dbo.Customers.nOrders, dbo.Customers.Concurrency, dbo.Customers.LegacyLN, dbo.Addresses.AddrType, dbo.Addresses.AddrLine1, dbo.Addresses.AddrLine2, " & _ 
"dbo.Addresses.City, dbo.Addresses.State, dbo.Addresses.Country, dbo.Addresses.PostalCode, dbo.Addresses.PhoneLandline, dbo.Addresses.Concurrency " & _ 
"FROM dbo.Customers INNER JOIN " & _ 
"dbo.Addresses ON dbo.Customers.CustAddrID = dbo.Addresses.AddrID " 
strSource = strSource & "WHERE dbo.Customers.CustomerID= " & lngID 

With Me        'Default is Set up for editing one record 
    If Not Nz(.RecordSource, vbNullString) = vbNullString Then 
     If .Dirty Then .Dirty = False 'Save any changes on the form 
     .RecordSource = vbNullString 
    End If 

    If rst Is Nothing Then   'Might not be first time through 
     DefaultSource = .RecordSource 
    Else 
     rst.Close 
     Set rst = Nothing 
    End If 
End With 

Set rst = New ADODB.Recordset 
Call setupformrecordset(dbconn, rst, strSource) 'dbconn is a global variable 

With Me 
    Set .Recordset = rst 
End With 

End Sub 

le jeu d'enregistrements renvoyé par setupformrecordset est entièrement actualisable, et sa propriété .Prend montre. Il peut être édité et mis à jour dans le code.

Le formulaire entier, cependant, est en lecture seule, même si ses propriétés .AllowEdits et .AllowAdditions sont toutes deux vraies. Même les champs du côté droit (le côté 'plusieurs') ne peuvent pas être édités.

La suppression de la clause INNER JOIN du TSQL (en limitant strSource à une table) rend le formulaire entièrement modifiable.

J'ai vérifié que le TSQL inclut des champs de clé primaire des deux tables, et chaque table inclut un champ d'horodatage pour la simultanéité.

J'ai essayé de modifier les propriétés .CursorType et .CursorLocation du jeu d'enregistrements en vain.

Qu'est-ce que je fais mal?

+0

"Bien que la méthode Supports puisse renvoyer True pour une fonctionnalité donnée, elle ne garantit pas que le fournisseur peut rendre la fonctionnalité disponible dans toutes les circonstances La méthode Supports renvoie simplement si le fournisseur peut prendre en charge la fonctionnalité spécifiée. Par exemple, la méthode Supports peut indiquer qu'un objet Recordset prend en charge les mises à jour, même si le curseur est basé sur une jointure de table multiple - certaines colonnes ne peuvent pas être mises à jour. " - http://msdn.microsoft.com/en-us/library/ms676500%28VS.85%29.aspx – barrowc

+1

Ce type de code: "If Not Nz (.RecordSource, vbNullString) = vbNullString Then "me fait mal à la tête Pourquoi pas" If Not IsNull (.RecordSource) "? Si .RecordSource ne peut pas être nul et est un ZLS lorsqu'il est vide, alors" Len (.RecordSource) = 0 " serait le bon test –

Répondre

0

Je pense que vous souhaitez définir la propriété dynamique Unique Table sur le jeu d'enregistrements.

+0

Merci pour la suggestion - j'ai essayé, mais cela n'a fait aucune différence. –

0

Une solution de contournement que j'ai trouvée est d'utiliser une clause 'IN'. Par exemple:

SELECT c.* 
FROM CATEGORY  c 
WHERE c.category_id IN (
      SELECT p.category_id 
      FROM PRODUCT  p 
      JOIN CUST_ORDER o ON o.product_id = p.product_id 
      WHERE p.product_type = 'Widget' 
      AND  o.units   > 50 
     ) 

De toute évidence, les valeurs codées en dur peuvent être transmises dans le sous-programme (et lier des variables utilisées). La chose importante à noter est que la clause IN peut avoir un nombre quelconque de jointures et que le Resultset peut toujours être mis à jour.

Si vous avez besoin de champs provenant de plusieurs tables, vous pouvez essayer de créer une vue de base de données et/ou d'utiliser DLookup().