Neuigkeiten:

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

Mobiles Hauptmenü

ADODB Recordset-holen in Modul auslagern

Begonnen von datekk, Oktober 11, 2016, 14:04:36

⏪ vorheriges - nächstes ⏩

datekk

Hi,

ich stelle meine Datenbank schritt für Schritt von Tabellen auf Recordsets um, welche von einer SQL Datenbank geholt werden. Bei einem Formular habe ich es wie folgt im Klassenmodul umgesetzt:


Option Compare Database
Option Explicit
Dim rs As New ADODB.Recordset
Dim con As New ADODB.Connection
Dim sql As String


Private Sub Form_Load()
  holeRecordset
End Sub

Sub holeRecordset()
Dim sql As String
sql = "EXEC dbo.spkundensuche 1, 2"

VerbindungStellen

Set rs = New ADODB.Recordset
With rs
    .Source = sql
    .ActiveConnection = con
    .CursorType = adOpenKeyset
    .LockType = adLockReadOnly
    .Open
End With

Set Me.Recordset = rs

rs.Close

End Sub


Sub VerbindungStellen()

With con
.Provider = "MSDataShape"
.ConnectionString = "DATA PROVIDER=SQLOLEDB.1;Server=*************************;"
.CursorLocation = adUseServer
.Open

End With
   
End Sub


Nun möchte ich aber die Subs in eine Funktion in einem normalen Modul auslagern. Hierbei sollte es so sein, dass ich in jedem Formular im Ereignis "beim Laden" mit einer einfachen Codezeile den Recordset holen kann. Dies sollte dann ungefähr wie folgt aussehen:


Private Sub Form_Load()

    Set Me.Recordset = Recordsetholen, "sql-Befehl"

End Sub


Leider kenne ich mich noch nicht so gut damit aus, wie ich die Variablen - Gültigkeit hierfür legen muss und wie die Variablen dann innerhalb der neuen Funktionen zu verbinden sind (ByVal // ByRef)....

Weiterhin sollte der Recordset bis zum schließen des Fensters geöffnet sein, damit Änderungen am Datensatz auch übernommen werden können. Beim schließen des Fensters müsste der Recordset und die Verbindung dann sicher irgendwie geschlossen werden.

Ich freue mich auf Eure Hilfen dazu.

LG
datekk
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

Wurliwurm

#1
Hi,

ich hatte hier vor einiger Zeit doch funktionierende Beispiele gepostet...

Es gibt folgende Möglichkeiten, die Referenz auf ein Recordset in ein Formular zu bekommen.

Entweder über eine öffentliche Funktion, die als Rückgabewert ein Recordset hat.
Public Function getDaten() as ADODB.Recordset
Sie wird vom Formular so aufgerufen
Dim rs as ADODB.Recordset (Im Formular)
Set rs = getDaten() (Im Öffnen-Ereignis)

Oder über einen Referenzparameter in einem Sub
Public Sub getDaten(ByRef rs ADODB.Recordset)
Dim rs as ADODB.Recordset (im Formular)
Call getDaten(rs)

Ein Übergabeparameter byval würde keinen Sinn machen und er wird auch stillschweigend beim kompilieren so behandelt, als ob man byref geschrieben hätte.

Nachdem Du die Referenz auf das Recordset hast, kannst Du mit diesem auch alles machen, zu Beispiel dieses schließen bei Schließen des Formulars.

datekk

Hi Wurliwurm,

Deine Beispiele sind bei mir auch Grundlage der technischen Realisierung innerhalb der Formulare, und dort funktioniert es auch super. Nun möchte ich die Subs sozusagen in Funktionen in einem Modul "zentralisieren" damit ich nicht jedes Klassenmodul so aufblähen muss. Mein Ziel ist es, meine Datenbank völlig ohne eingebundene Tabellen zu betreiben und die Arbeit vollständig dem SQL Server aufzubürden... einfach der Geschwindigkeit und Datensicherheit wegen. Daher muss ich nun alle der gefühlten 1000 Formular so umstellen und suche daher nach einem optimierten Recordset.

Ich danke Dir für Deine Ansätze und melde mich kurzfristig wieder.

LG
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

Wurliwurm

Zitat von: datekk am Oktober 12, 2016, 14:33:02
Daher muss ich nun alle der gefühlten 1000 Formular so umstellen und suche daher nach einem optimierten Recordset.

Der Ansatz ist sehr gut und wird auch funktionieren.

Du könntest eine zentrale und generische Funktion schreiben, welche Recordsets zurückgibt für einen SQL-String. In der Art:
Public Function holeRecordset(ByVal strSQL as String) as ADODB.Recordset

Wie bei Endlosformularen die Anzeige im Formular mit CursorLocation aduseServer sein wird, weiß ich nicht sicher. Ich umschiffe das ja mit dem Kopieren in lokale ungebundene Recordsets mit aduseClient, was ein kleiner Overhead ist, aber kaum spürbare Performancenachteile hat.

In meinen Anwendungen ist die ADODB.Connection immer eine public Variable. Die Connection wird gleich beim Starten des Access-Clients geöffnet und bleibt immer offen. Es ist völlig unnötig, sie zwischendrin neu aufzubauen. Bei Abstürzen oder Netzwerkfehlern mit Trennung des Clients wird der Server erkennen, daß die Connection weggebrochen ist, das ist sauber im Gegensatz zu filebasierten Backends.

Viel gibt es m.E. nicht zu tun, es gehört alles zum Verbindungsaufbau (conn.open) und Recordset-Öffnen (conn.open) in die Module. In den Formularen higegen wird nur ein Recordset referenziert mit
Dim rs as ADODB.Recordset
und die Felder müssen angebunden werden.

''***Felder anbinden an das Recordset***
Set Me.Recordset = rs
txt1.ControlSource = "Betrag"
txt2.ControlSource = "Kontonummer"



Josef P.

#4
Hallo!

Man kann bei Bedarf auch das Recordset mit adUseClient öffnen. (Ist meiner Meinung nach aber nur für das Ändern der Daten über das gebundene Formular bzw. für das Kappen der Verbindung erforderlich.)
Eine Standardroutine von mir (Auszug aus der AdodbHandler-Klasse):
Public Function OpenRecordset(ByVal Source As String, _
                     Optional ByVal CursorType As ADODB.CursorTypeEnum = ADODB.CursorTypeEnum.adOpenForwardOnly, _
                     Optional ByVal LockType As ADODB.LockTypeEnum = ADODB.LockTypeEnum.adLockReadOnly, _
                     Optional ByVal CursorLocation As ADODB.CursorLocationEnum = ADODB.CursorLocationEnum.adUseServer, _
                     Optional ByVal DisconnectedRecordset As Boolean = False) As ADODB.Recordset
' gibt geöffnetes ADO-Recordset zurück
' Source = SQL-Anweisung

   Dim rst As ADODB.Recordset

   Set rst = New ADODB.Recordset
   With rst
      .CursorLocation = CursorLocation
      .Open Source, Me.CurrentConnection, CursorType, LockType
     
      If DisconnectedRecordset Then
         Set .ActiveConnection = Nothing
      End If
     
   End With
   Set OpenRecordset = rst
   
End Function


Der Aufruf erfolgt dann z. B. mit
Set FormRef.Recordset = StatischeAdodbHandlerInstanz.OpenRecordset("[SQL-Anweisung]", adOpenKeyset, adLockReadOnly, adUseClient)
.. das sollte bei Endlosformularen ohne Probleme laufen.
Anm.: Den CursorType passt sich Access (glaube ich zu erinnern) selbst an, sobald man das Recordset an das Formular bindet.

Bezüglich gebundener Datenfelder gehe ich pragmatisch vor:
Ich stelle als Datenquelle einen SQL-Ausdruck mit einer Dummy-Tabelle um alle benötigten Datenfelder im Formularentwurf verwenden zu können und binde damit die Steuerelemente. Dann muss man später mittels Code nichts anpassen. ;)
Prinzip: select 0 as Feld1, "" as Feld2, .. from EineBeliebigeClientTabelle where 1=0

mfg
Josef