Neuigkeiten:

Wenn ihr euch für eine gute Antwort bedanken möchtet, im entsprechenden Posting einfach den Knopf "sag Danke" drücken!

Mobiles Hauptmenü

Formular mit ADODB Recordset aktualisieren

Begonnen von datekk, Januar 23, 2017, 16:10:26

⏪ vorheriges - nächstes ⏩

datekk

Hallo,

ich habe ein Formular, welches ich an ein ADODB Recordset binde. Die Datenquelle besteht allerdings aus einer Abfrage, die mehrere Felder anderer Tabellen abfragt.

Der Datensatz wird im Formular richtig angezeigt, jedoch kann ich keine Daten ändern. Wenn ich das Formular schließe, werden alle Daten auf den Urzustand zurück gesetzt.

Der ADODB Recordset holt sich die Daten von einem SQL Server, wo eine gespeicherte Prozedur aufgerufen wird, die wiederum den Datensatz liefert.

Wie kann ich also so einen Datensatz aktualisieren der auf mehreren Tabellen beruht?
Access 2016 mit SQL Server Backend. Bereits umgesetzt: Access mit MS SQL Backend,  ADODB Formularbindung, Streamen von Dateien zum SQL Server und zurück (Filestream), Drag&Drop Dateiupload zum Server, CTI / TAPI Integrierung in Access Anwendung - Nutzung auch über Remote Desktop, selbst aktualisierendes Access Frontend auf entfernten Rechnern (Upgrade). Berichte / Kreuztabellen mit SQL Server Backend, Mail Tagging, Outlook Steuerung über Access und umgekehrt // Grundwissen in .Net Core & Blazor Apps

ebs17

Eine Aktualisierbarkeit erreicht man, wenn man sich auf Datensätze in Tabellen konzentriert (da liegen sie nämlich wirklich).

Also sollte man aus dem zu ändernden Feld auf den Datensatz der beteiligten Tabelle schließen können und auf diesen dann die Änderung anwenden,
- per gesondertem Änderungsformular zur Tabelle,
- per Aktionsabfrage
Mit freundlichem Glück Auf!

Eberhard

datekk

Ist es denn eigentlich möglich einem Steuerelement seine Herkunft zu entlocken? Also kann man z.B. bei Me.Textfeld irgendwie herausfinden, woher es seine Daten bezieht?

Also so z.B.: debug.print me.textfeld.herkunftstabelle.name?

Denn irgendwie muss ja im Recordset die Herkunft auch hinterlegt sein.

Meine Idee ist, die Steuerelemente via Do Loop zu durchlaufen, die Datenherkunft abzufragen und somit für jedes Feld eine Aktualisierungsabfrage durchzuführen. Ggf. lässt sich dies ja noch auf geänderte Felder reduzieren...

Ist das möglich?
Access 2016 mit SQL Server Backend. Bereits umgesetzt: Access mit MS SQL Backend,  ADODB Formularbindung, Streamen von Dateien zum SQL Server und zurück (Filestream), Drag&Drop Dateiupload zum Server, CTI / TAPI Integrierung in Access Anwendung - Nutzung auch über Remote Desktop, selbst aktualisierendes Access Frontend auf entfernten Rechnern (Upgrade). Berichte / Kreuztabellen mit SQL Server Backend, Mail Tagging, Outlook Steuerung über Access und umgekehrt // Grundwissen in .Net Core & Blazor Apps

PhilS

Zitat von: datekk am Januar 23, 2017, 16:10:26Wie kann ich also so einen Datensatz aktualisieren der auf mehreren Tabellen beruht?
Mal davon abgesehen, dass diese Formulierung in sich schon widersprüchlich ist, kannst du mehrere Tabellen auf einmal nur dann aktualisieren, wenn du die Logik der Aktualisierung selbst ausprogrammierst. - Das wird mit gebundenen Formularen evtl. schwierig, könnte aber mit einem komplett ungebundenem Recordset gehen.

In der Regel ist die einfachste, und meist auch beste Option, die dem Rat von ebs17 zu folgen und sich auf eine Tabelle zu konzentrieren.
Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor

datekk

Jo, bin schon am ändern und versuche die Felder der anderen Tabelle via Unterformular einzufügen.
Access 2016 mit SQL Server Backend. Bereits umgesetzt: Access mit MS SQL Backend,  ADODB Formularbindung, Streamen von Dateien zum SQL Server und zurück (Filestream), Drag&Drop Dateiupload zum Server, CTI / TAPI Integrierung in Access Anwendung - Nutzung auch über Remote Desktop, selbst aktualisierendes Access Frontend auf entfernten Rechnern (Upgrade). Berichte / Kreuztabellen mit SQL Server Backend, Mail Tagging, Outlook Steuerung über Access und umgekehrt // Grundwissen in .Net Core & Blazor Apps

PhilS

Zitat von: datekk am Januar 23, 2017, 17:53:34
Ist es denn eigentlich möglich einem Steuerelement seine Herkunft zu entlocken? Also kann man z.B. bei Me.Textfeld irgendwie herausfinden, woher es seine Daten bezieht?
[...]
Denn irgendwie muss ja im Recordset die Herkunft auch hinterlegt sein.
Ein ADODB.Field hat in seiner Properties-Auflistung eine Property BASETABLENAME. - Ob dort etwas brauchbares drin steht, hängt natürlich von der Logik in der SP ab, die die Daten liest und an den Client liefert.
Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor

Beaker s.a.

Hallo,
ZitatIst es denn eigentlich möglich einem Steuerelement seine Herkunft zu entlocken? Also kann man z.B. bei Me.Textfeld irgendwie herausfinden, woher es seine Daten bezieht?
Vielleicht indem man die RecordSource des Formulars und die ControlSource des
Textfeldes ausliest?
gruss ekkehard
Alles, was geschieht, geschieht. - Alles, was während seines Geschehens etwas anderes geschehen lässt, lässt etwas anderes geschehen. - Alles, was sich selbst im Zuge seines Geschehens erneut geschehen lässt, geschieht erneut. - Allerdings tut es das nicht unbedingt in chronologischer Reihenfolge.
(Douglas Adams, Mostly Harmless)

markusxy

#7
Zitat von: datekk am Januar 23, 2017, 16:10:26
Wie kann ich also so einen Datensatz aktualisieren der auf mehreren Tabellen beruht?

Das ist normalerweise kein Problem. Im Gegenteil, grade in diesem Punkt ist ADO wesentlich besser wie DAO. Nur Felder mit berechneten oder aggrigierten Werten kann man nicht ändern. Die restlichen Felder können normal immer aktualisiert werden.

Falls die Mindestanforderungen für das Update erfüllt sind, bleibt noch das Formular.
Auch wenn sich das Recordset aktualisieren lässt, spielt das Formular manchmal nicht mit. Die Implementierung in Access Forms ist sehr mangelhaft. Ich verwende daher bei ADO RS für Endlosformulare in der Regel ein Datagrid.
Die Frage ist jetzt, ob sich das Recordset ohne Bindung an ein Formular aktualisieren lässt.
Wenn nein, dann poste einfach mal die Abfrage aus der SP und zeige den Code wie du das Recordset öffnest.

LG Markus

PhilS

Zitat von: markus888 am Januar 23, 2017, 23:38:56Falls die Mindestanforderungen für das Update erfüllt sind, bleibt noch das Formular.
Auch wenn sich das Recordset aktualisieren lässt, spielt das Formular manchmal nicht mit.
Wenn ein Aktualisierungsproblem nur aus dem Formular resultiert, lässt sich das in vielen Fällen durch Setzten der UniqueTable- und/oder ResyncCommand-Property beheben.
Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor

datekk

#9
Danke Markus und PhilS. Ich habe noch weitere Fragen zu Euren Antworten:

ZitatFalls die Mindestanforderungen für das Update erfüllt sind, bleibt noch das Formular.
Was sind die Mindestanforderungen? Also in der "normalen" Access Umgebung basiert das Formular auf einer Abfrage von mehreren Tabellen und hier ist das Formular aktualisierbar. Ich habe einfach die Abfrage .. also die SELECT Anweisung in die Open Einstellungen des RS genommen, bzw. auf Basis der Abfrage eine gespeicherte Prozedur erstellt, die ich via EXEC aufrufe.

ZitatDie Frage ist jetzt, ob sich das Recordset ohne Bindung an ein Formular aktualisieren lässt.
Wie finde ich das heraus?

Zitatlässt sich das in vielen Fällen durch Setzten der UniqueTable- und/oder ResyncCommand-Property beheben.
Wie mache ich das und wo?


Die Ursprüngliche Abfrage ist:
SELECT Kundenliste.ID_Kunde, Kundenliste.Type, Firma.Firmenname, Firma.Straße, Firma.PLZ, Firma.Ort, Ansprechpartner.Anrede, Ansprechpartner.Vorname, Ansprechpartner.Nachname, Kundenliste.Nachverfolgung, Kundenliste.Uhrzeit, Kundenliste.VertriebsID, Kundenliste.Erstellungsdatum, Kundenliste.Status_1, Kundenliste.Vertriebsphase, Kundenliste.Titel, Kundenliste.Quelle, Kundenliste.[geschlossen am], Kundenliste.Neukunde, Firma.ID_Kunde AS ParentID, Kundenliste.GrandParentContactServiceID, Kundenliste.Type, Kundenliste.IrisSubType, Ansprechpartner.WorkPhoneNum, Ansprechpartner.MobilePhoneNum, Ansprechpartner.EmailAddress1, Kundenliste.KundenIdRef, Kundenliste.VorgangsFarbe, Kundenliste.AutoPilotOn, Kundenliste.AutoPilotArt, Kundenliste.AutoPilotDatumLetzteAktion

FROM (Kundenliste LEFT JOIN Kundenliste AS Firma ON Kundenliste.ParentIDNeu = Firma.ID_Kunde) LEFT JOIN Kundenliste AS Ansprechpartner ON Kundenliste.GrandParentContactServiceID = Ansprechpartner.ID_Kunde

WHERE (((Kundenliste.Type)=3));


Code in gespeicherter Prozedur:


SELECT Kundenliste.ID_Kunde, Kundenliste.Type, Firma.Firmenname, Firma.Straße, Firma.PLZ, Firma.Ort, Ansprechpartner.Anrede, Ansprechpartner.Vorname, Ansprechpartner.Nachname, Kundenliste.Nachverfolgung, Kundenliste.Uhrzeit, Kundenliste.VertriebsID, Kundenliste.Erstellungsdatum, Kundenliste.Status_1, Kundenliste.Vertriebsphase, Kundenliste.Titel, Kundenliste.Quelle, Kundenliste.[geschlossen am], Kundenliste.Neukunde, Firma.ID_Kunde AS ParentID, Kundenliste.GrandParentContactServiceID, Kundenliste.Type, Kundenliste.IrisSubType, Ansprechpartner.WorkPhoneNum, Ansprechpartner.MobilePhoneNum, Ansprechpartner.EmailAddress1, Kundenliste.KundenIdRef, Kundenliste.VorgangsFarbe, Kundenliste.AutoPilotOn, Kundenliste.AutoPilotArt, Kundenliste.AutoPilotDatumLetzteAktion
FROM (Kundenliste LEFT JOIN Kundenliste AS Firma ON Kundenliste.ParentIDNeu = Firma.ID_Kunde) LEFT JOIN Kundenliste AS Ansprechpartner ON Kundenliste.GrandParentContactServiceID = Ansprechpartner.ID_Kunde
WHERE (((Kundenliste.ID_Kunde)=@intID) AND ((Kundenliste.Type)=3));





Aufruf im Klassenmodul:

Private Sub Form_Open(Cancel As Integer)

    Set Me.Recordset = SQLRecordset("EXEC dbo.spVerkaufschanceHolen " & Me.OpenArgs)
   
End Sub


Funktion SQLRecordset:


Public Function SQLRecordset(sql As String) As ADODB.Recordset
On Error Resume Next

    Set SQLRecordset = New ADODB.Recordset
    With SQLRecordset
        .ActiveConnection = Connection
        .CursorLocation = adUseServer
        .CursorType = adOpenKeyset
        .LockType = adLockOptimistic
        .Source = sql
        .Open
    End With

Private Function Connection() As ADODB.Connection

    Set Connection = New ADODB.Connection
    With Connection
        .ConnectionString = "DATA PROVIDER=SQLOLEDB.1;Server=**************;DATABASE=*******;UID=******;PWD=*********"
        .CursorLocation = adUseServer
        .Provider = "MSDataShape"
        .Open
    End With
   

End Function




Access 2016 mit SQL Server Backend. Bereits umgesetzt: Access mit MS SQL Backend,  ADODB Formularbindung, Streamen von Dateien zum SQL Server und zurück (Filestream), Drag&Drop Dateiupload zum Server, CTI / TAPI Integrierung in Access Anwendung - Nutzung auch über Remote Desktop, selbst aktualisierendes Access Frontend auf entfernten Rechnern (Upgrade). Berichte / Kreuztabellen mit SQL Server Backend, Mail Tagging, Outlook Steuerung über Access und umgekehrt // Grundwissen in .Net Core & Blazor Apps

markusxy


ZitatDie Frage ist jetzt, ob sich das Recordset ohne Bindung an ein Formular aktualisieren lässt.

Wie finde ich das heraus?


Einfach testen.

Zitatlässt sich das in vielen Fällen durch Setzten der UniqueTable- und/oder ResyncCommand-Property beheben.  Wie mache ich das und wo?


Die VBA Hilfe wäre da ganz ein heißer Tipp.

LG Markus

markusxy

Zitat von: PhilS am Januar 24, 2017, 10:53:20
Wenn ein Aktualisierungsproblem nur aus dem Formular resultiert, lässt sich das in vielen Fällen durch Setzten der UniqueTable- und/oder ResyncCommand-Property beheben.

Meine Angaben zur Aktualisierbarkeit haben sich auf einen Client Cursor bezogen (gewöhnlich die erste Wahl bei Access - da dieser bei allen Steuerelementen erforderlich ist). Da kann es vorkommen, das nur ein Teil der Felder aktualisierbar ist. Da ich auch kein Access Form mehr für ADO einsetzte, interessiert es mich auch nicht wahnsinnig ob das funktioniert. Verfügst du da über Erfahrung?

LG Markus

PhilS

Zitat von: datekk am Januar 24, 2017, 10:58:24
Zitatlässt sich das in vielen Fällen durch Setzten der UniqueTable- und/oder ResyncCommand-Property beheben.
Wie mache ich das und wo?
In einem ADP ganz normal in den Formulareigenschaften. In einer MDB/ACCDB sind diese Eigenschaften im Formulardesigner ausgeblendet, aber sie können auch dort per VBA-Code gesetzt werden.
Sinnvollerweise machst du das nachdem du das Recordset des Formulars zugewiesen hast.

Ich glaube dein Hauptproblem ist aber die Cursor-Einstellung deines Recordsets. Du brauchst einen clientseitigen (adUseClient) Cursor, damit deine Recordsets, an ein Formular gebunden, aktualisierbar sind.
Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor

datekk

Alles klar, ich werde das mal probieren. Ein Problem habe ich noch: Datumsfelder. Der SQL Server liefert mir das Datum so: 2017-01-23

Wie kann ich das Datum in einem Textfeld ganz normal darstellen (23.01.2017) UND auch aktualisieren? optimaler Weise mit der Datumsauswahl (also wo sich das kleine Kalenderfenster öffnet).

Ich hatte es schon mit dem Microsoft Steuerelement DatePicker versucht. Dieses stellt das Datum richtig dar, bei Änderung erhalte ich jedoch die Fehlermeldung, dass das Feld zu klein wäre für die Datenmenge. Datentyp im SQL ist Date. Ich nehme an, das Steuerelement liefert DateTime.
Access 2016 mit SQL Server Backend. Bereits umgesetzt: Access mit MS SQL Backend,  ADODB Formularbindung, Streamen von Dateien zum SQL Server und zurück (Filestream), Drag&Drop Dateiupload zum Server, CTI / TAPI Integrierung in Access Anwendung - Nutzung auch über Remote Desktop, selbst aktualisierendes Access Frontend auf entfernten Rechnern (Upgrade). Berichte / Kreuztabellen mit SQL Server Backend, Mail Tagging, Outlook Steuerung über Access und umgekehrt // Grundwissen in .Net Core & Blazor Apps

markusxy

Zitat von: datekk am Januar 25, 2017, 09:28:14
Der SQL Server liefert mir das Datum so: 2017-01-23

Welchen Datentyp zeigt das Recordset für das Datum?