Benutzer mit den meisten Antworten
ACCESS und Datagrid...

Frage
-
Habe jetzt mal eine simple Tabelle genommen ( einer der kleinsten von unseren Kunden mit ca. 300000 Sätzen )
Binde die ACCESS Mappe mit :
Dim cString As String
Dim oDb As New OleDbConnection
Dim oDs As System.Data.DataSet
Dim oAdapter As System.Data.OleDb.OleDbDataAdapter
cDatenpfad = "C:\winprojekte\vbwinwawi\daten\"
cDatenbank = "WinWaWi.mdb"
oDb = WindowsApplication1.WinWaWi.oDatenbanken.oConnectioncString = "SELECT Top 10 * FROM Artikel"
oAdapter = New System.Data.OleDb.OleDbDataAdapter(cString, oDb)
oDs = New System.Data.DataSet
oAdapter.Fill(oDs)Me.DataGridView1.DataSource = oDs.Tables(0)
oConnection kommt aus den ersten Versuchen einer "globalen" Klasse :
oConnection.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;" &
"Data Source=" + cDatenpfad + cDatenbankoConnection.Open()
Das dauert ca. 11 Sekunden bis das Grid auf einem lokalen Rechner mit power unter der Haube angezeigt wird...
Mache ich hier was falsch ? 11 Sekunden sind für die lächerliche Anzahl definitiv viel zu viel, zumal das ganze noch lokal auf C:\ liegt...
In ACCESS selber wenn ich da n doppelklick auf die Tabelle mache sind die Daten ja auch in einer gefühlten Sekunde vorhanden und werden angezeigt.
Gibts also irgendwie eine nativere Anbindung an ACCESS mit VB ?
Danke euch,
Mario
Antworten
-
Hallo Mario,
11 Sekunden sind wirklich reichlich viel...
Hängt da ein freundlicher Virenscanner (oder anderes) dazwischen?Der Zugriff via Microsoft.Jet.OLEDB.4.0 ist der bevorzugte Weg für Access Datenbanken (zumindest bis 2003).
Was unter .NET ebenso fix (oder langsam) geht, als wenn Du die Datenank unter Access selbst
oder einer anderen OleDb Anwendung (z. B. VB Classic) öffnest.Anmerkungen am Rande:
Du solltest Deine Verbindungszeichenfolge in die Settings verlagern
und jeweils nur für den Zugriff öffnen, klassisches Muster wäre dabei:Public Function GetArtikelDataSet() As DataSet Dim dataSet As New DataSet("ArtikelDataSet") Using adapter As New OleDbDataAdapter( _ "SELECT TOP 10 * FROM Artikel", _ My.Settings.AccessConnectionString) adapter.MissingMappingAction = MissingMappingAction.Passthrough adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey adapter.Fill(dataSet, "Artikel") End Using Return dataSet End Function
Das Connection Pooling sorgt schon für ein Recyceln der Verbindung.
(Und dauert bei meinen Artikeln um die 30 ms, ob 10 oder 1000 Zeilen)Präfixe wie "o" sind überflüssig, denn unter .NET ist alles ein Objekt - auch ein String ;-)
Schau Dir bei Gelegenheit mal an: Entwurfsrichtlinien zum Entwickeln von Klassenbibliotheken
Damit wird der Code für Dich und andere am Ende leserlicher.Gruß Elmar
- Als Antwort markiert Robert Breitenhofer Montag, 5. Juli 2010 11:13
-
Hi Mario,
Access baut die Bindung zur Datenbank bereits mit dem Laden der Access-Datei auf. Für die Anzeige werden dann erst einmal nur die Daten geladen, die zur Anzeige benötigt werden. Der Rest wird nachgeladen.In Deinem Beispiel baust du die Verbindung auf, lädst dann ALLE Daten und bindest dann die Daten an das Grid. Das dauert natürlich länger als in der Access-Oberfläche. Wenn du es genau so machen willst wie in der Access-Oberfläche, dann lade die Daten asynchron nach. Hier mal eine Demo dazu:
UI-Klasse (einfach in den Codeteil eines leeren Windows in eine VB Anwendung kopieren):
Public Class Form1 Private vm As New ViewModel Private btnload As New Button With {.Text = "Laden", .Dock = DockStyle.Top} Private dgv As New DataGridView With {.Dock = DockStyle.Fill, .DataSource = vm.BS} Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.Controls.AddRange(New Control() {dgv, btnload}) AddHandler btnload.Click, AddressOf vm.LoadData End Sub End Class
Und dazu die Klasse mit der Ladefunktion:
Imports System.Data.OleDb Imports System.ComponentModel Public Class ViewModel Public Property BS As New BindingSource Private cn As New OleDbConnection(My.Settings.cnMdb) Private da As New OleDbDataAdapter With {.MissingSchemaAction = MissingSchemaAction.AddWithKey} Private cmd As New OleDbCommand("", cn) Private dt As New DataTable Dim WithEvents bgw As New BackgroundWorker Public Sub LoadData(ByVal sender As Object, ByVal e As EventArgs) cmd.CommandText = "SELECT top 100 * FROM Status" da.SelectCommand = cmd da.Fill(dt) da.SelectCommand = cmd BS.DataSource = dt bgw.RunWorkerAsync() End Sub Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgw.DoWork Dim dt2 As New DataTable cmd.CommandText = "SELECT * FROM Status" da.Fill(dt2) dt.Merge(dt2) End Sub Private Sub bgw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted BS.ResetBindings(False) End Sub End Class
--
Viele Gruesse
Peter- Als Antwort markiert Robert Breitenhofer Montag, 5. Juli 2010 11:13
-
so, nach einer Nacht und einem ordentlichen Kaffee denke ich habe ich meinen "Fehler" gefunden...
Ich hatte angenommen das ich die ACCESS-Tables mit meiner dBase Datenbank vergleichen kann. Da ACCESS die ALLE Daten ja sofort zu verfügung stellt wenn sie geöffnet wird.. Dem scheint ja aber nicht so zu sein. Wenn ich die ACCESS wie eine SQL Tabelle vergleiche dann ist die Performance ok .. muss ich mein Konzept halt doch noch mal ändern, erst den Benutzer zu fragen "welche Daten möchtest du dann sehen" und dann erst mit einer WHERE Bedingung die Ergebnisse liefern. Unter dem Gesichtspunkt ist die ACCESS Tabelle auf unserem künstlich gedrosselten Programmier-Test-Server dann doch sogar ein Tick schneller als der SQL2005...
@Elmar .. der Zeitverlust passiert wirklich nur im Fill() nicht das Datagrid, das stellt die Daten in einwandfreier Zeit zur Verfügung...
Danke euch !
- Als Antwort markiert Robert Breitenhofer Montag, 5. Juli 2010 11:12
Alle Antworten
-
Hallo Mario,
cString = "SELECT Top 10 * FROM Artikel"
Das dauert ca. 11 Sekunden bis das Grid auf einem lokalen Rechner mit power unter der Haube angezeigt wird...
Mache ich hier was falsch ? 11 Sekunden sind für die lächerliche Anzahl definitiv viel zu viel, zumal das ganze noch lokal auf C:\ liegt...
pack mal ein ORDER BY <Spalte> ins Statement. Alternativ (nur zum probieren) das hier:
SELECT Spalte1, Spalte2, ... FROM Artikel WHERE <IdSpalte> < 100
Wenn letzteres schneller ist, liegts wohl an fehlenden Indizes.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hallo Mario,
11 Sekunden sind wirklich reichlich viel...
Hängt da ein freundlicher Virenscanner (oder anderes) dazwischen?Der Zugriff via Microsoft.Jet.OLEDB.4.0 ist der bevorzugte Weg für Access Datenbanken (zumindest bis 2003).
Was unter .NET ebenso fix (oder langsam) geht, als wenn Du die Datenank unter Access selbst
oder einer anderen OleDb Anwendung (z. B. VB Classic) öffnest.Anmerkungen am Rande:
Du solltest Deine Verbindungszeichenfolge in die Settings verlagern
und jeweils nur für den Zugriff öffnen, klassisches Muster wäre dabei:Public Function GetArtikelDataSet() As DataSet Dim dataSet As New DataSet("ArtikelDataSet") Using adapter As New OleDbDataAdapter( _ "SELECT TOP 10 * FROM Artikel", _ My.Settings.AccessConnectionString) adapter.MissingMappingAction = MissingMappingAction.Passthrough adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey adapter.Fill(dataSet, "Artikel") End Using Return dataSet End Function
Das Connection Pooling sorgt schon für ein Recyceln der Verbindung.
(Und dauert bei meinen Artikeln um die 30 ms, ob 10 oder 1000 Zeilen)Präfixe wie "o" sind überflüssig, denn unter .NET ist alles ein Objekt - auch ein String ;-)
Schau Dir bei Gelegenheit mal an: Entwurfsrichtlinien zum Entwickeln von Klassenbibliotheken
Damit wird der Code für Dich und andere am Ende leserlicher.Gruß Elmar
- Als Antwort markiert Robert Breitenhofer Montag, 5. Juli 2010 11:13
-
"Elmar Boye" schrieb im Newsbeitrag news:cdc8da08-fbfc-44c1-a250-3e9a681e88ba...
...
Anmerkungen am Rande:
Du solltest Deine Verbindungszeichenfolge in die Settings verlagern
und jeweils nur für den Zugriff öffnen, klassisches Muster wäre dabei:...
Das Connection Pooling sorgt schon für ein Recyceln der Verbindung.
(Und dauert bei meinen Artikeln um die 30 ms, ob 10 oder 1000 Zeilen)Hi Elmar,
für Acces ist das eine denkbar ungünstige Arbeitsweise. Leider funktioniert das ConnectionPooling mit Access bei größerer Anwenderzahl nicht wirklich. Ich habe da mal viel Aufwand in die Suche undefinierter Abbrüche gesteckt und Ursache war letztendlich das ständige Öffnen und Schließen der Verbindung im Programm mit eingeschaltetem ConnectionPooling. Die Fehlerausschriften sagten nur "undefinierter Fehler" und im Fehlerfall war irgendwie die ldb kaputt. Warum beim ConnectionPooloing die ldb zerstört wird, kann ich nicht sagen. Der Fehler war in einem Strestest mit einem eifachen Programm mit hoher Belastung (mehrere Anwender, länger andauernde Abfragen) sporadisch nachweisbar. Das Programm selbst war ein WebService, der mit der Jet 4.0 mit einer Access 2003 Datei gearbeitet hat. Da dieser Fehler immer bei höherer Belastung auftrat und ich gerade dann immer wenig Zeit hatte, habe ich das Problem nicht weiter verfolgt und habe einfach nur den Zugriff mit gleichen SQL Anweisungen auf einem SQL 2000 Server ausgeführt. Da traten keine Fehler mehr auf.
--
Viele GruessePeter
-
huhu,
wie gesagt, ohn Änderung an der Tabelle, wenn ich die mit ACCESS doppelklicke, zack alle 30000 Datensätze sind da..
Hab ein ORDER BY Artikel eingenaut => keine Verbesserung
Eine direkte Feldauswahl mit Artikel, Nummer, Bezeichnung => bringt natürlich bisl was aber immernoch viiiel zu lange
Hab ein Primärschlüssel vergeben ( fehlte in der Tabelle noch ), aber auch das bringt keine Verbesserung...
Virenscanner ist ruhig, scannt nur einmal die Tabelle beim "open" ... so wie es sein soll...
Danke @Elmar für die Entwurfsrichtlinien... muss ich mich erst eingewöhnen ( bin noch DOS-Clipper und VO Syntaxe gewöhnt, wird etwas dauern bis ich mich da eingestellt habe auf VB )
Was könnte denn sonst für ein Problem da sein? Ich bin halt nur vewundert das mit ACCESS direkt alle Datensätze dsofort zu sehen sind ohne Erkennbare Verzögerung und unter VB mit diesem kleinen Knopf gefühlte 11 Sekunden dauert... sind zwar 30000, aber das eher die kleinere Varainte der Daten mit den ich hier hantiere :)
-
Hi Mario,
Access baut die Bindung zur Datenbank bereits mit dem Laden der Access-Datei auf. Für die Anzeige werden dann erst einmal nur die Daten geladen, die zur Anzeige benötigt werden. Der Rest wird nachgeladen.In Deinem Beispiel baust du die Verbindung auf, lädst dann ALLE Daten und bindest dann die Daten an das Grid. Das dauert natürlich länger als in der Access-Oberfläche. Wenn du es genau so machen willst wie in der Access-Oberfläche, dann lade die Daten asynchron nach. Hier mal eine Demo dazu:
UI-Klasse (einfach in den Codeteil eines leeren Windows in eine VB Anwendung kopieren):
Public Class Form1 Private vm As New ViewModel Private btnload As New Button With {.Text = "Laden", .Dock = DockStyle.Top} Private dgv As New DataGridView With {.Dock = DockStyle.Fill, .DataSource = vm.BS} Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.Controls.AddRange(New Control() {dgv, btnload}) AddHandler btnload.Click, AddressOf vm.LoadData End Sub End Class
Und dazu die Klasse mit der Ladefunktion:
Imports System.Data.OleDb Imports System.ComponentModel Public Class ViewModel Public Property BS As New BindingSource Private cn As New OleDbConnection(My.Settings.cnMdb) Private da As New OleDbDataAdapter With {.MissingSchemaAction = MissingSchemaAction.AddWithKey} Private cmd As New OleDbCommand("", cn) Private dt As New DataTable Dim WithEvents bgw As New BackgroundWorker Public Sub LoadData(ByVal sender As Object, ByVal e As EventArgs) cmd.CommandText = "SELECT top 100 * FROM Status" da.SelectCommand = cmd da.Fill(dt) da.SelectCommand = cmd BS.DataSource = dt bgw.RunWorkerAsync() End Sub Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgw.DoWork Dim dt2 As New DataTable cmd.CommandText = "SELECT * FROM Status" da.Fill(dt2) dt.Merge(dt2) End Sub Private Sub bgw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted BS.ResetBindings(False) End Sub End Class
--
Viele Gruesse
Peter- Als Antwort markiert Robert Breitenhofer Montag, 5. Juli 2010 11:13
-
Hallo Mario,
schon das einmalige Scannen bei Öffnen von Dateien (und vermutlich bei der LDB dito) würde mich nerven!
Und die 30ms waren inkl. einiger sinnfreier Bilddaten, die die in NG verwendete Beispieltabelle
vor etlichen Jahren mal verpaßt gekriegt hatte (fiel mir gerade erst auf ;-)
Auch haben Virenscanner oft die Angewohnheit unbekannte Programme genauer unter die Lupe
zunehmen, was den Start zusätzlich verzögert, da während einer Entwicklung immer ein neues entsteht.
Also lege den Scanner mal still bzw. schliesse das Verzeichnis mit der MDB/LDB aus.Der gezeigte Code-Schnippsel ist insofern auf Dauer ineffizienter, weil jedesmal das DataSet erzeugt werden muß,
was aber kaum den Unterschied erklären dürfte - günstiger ist ein einmaliges FillSchema (oder ein typisiertes DataSet ).
Auch muß beim Binden an das DataGridView einiges zusätzlich getan werden, wenn das Schema nicht von vornherein festliegt
Was aber alles mehr auf .NET Seite liegt und unabhängig von der Jet/OleDb immer passiert.Access ist im übrigen nur bedingt vergleichbar, da es "mogelt". Es zeigt das Datenblatt (oder Formular) bereits an,
sobald es genügend Daten für eine Seite zusammen hat. Ein DataAdapter muß aber erst alles lesen,
bevor die Anzeige überhaupt in die Gänge kommt.Um nur den Abruf zu messen, verwende die Stopwatch-Klasse , für oben:
Dim sw = Stopwatch.StartNew() Dim dataSet = GetArtikelDataSet() ' Me.DataGridView1.DataSource = dataSet ' Me.DataGridView1.DataMember = "Artikel" sw.Stop() Console.WriteLine("{0} => {1} ({2})", dataSet.Tables(0).TableName, dataSet.Tables(0).Rows.Count, sw.ElapsedMilliseconds)
und vergleiche mit/ohne Zuweisen der DataSource und auch nach meheren Durchläufen
(aber auch mit DataGridView bleibt es hier weit unter einer Sekunde).Gruß Elmar
-
so, nach einer Nacht und einem ordentlichen Kaffee denke ich habe ich meinen "Fehler" gefunden...
Ich hatte angenommen das ich die ACCESS-Tables mit meiner dBase Datenbank vergleichen kann. Da ACCESS die ALLE Daten ja sofort zu verfügung stellt wenn sie geöffnet wird.. Dem scheint ja aber nicht so zu sein. Wenn ich die ACCESS wie eine SQL Tabelle vergleiche dann ist die Performance ok .. muss ich mein Konzept halt doch noch mal ändern, erst den Benutzer zu fragen "welche Daten möchtest du dann sehen" und dann erst mit einer WHERE Bedingung die Ergebnisse liefern. Unter dem Gesichtspunkt ist die ACCESS Tabelle auf unserem künstlich gedrosselten Programmier-Test-Server dann doch sogar ein Tick schneller als der SQL2005...
@Elmar .. der Zeitverlust passiert wirklich nur im Fill() nicht das Datagrid, das stellt die Daten in einwandfreier Zeit zur Verfügung...
Danke euch !
- Als Antwort markiert Robert Breitenhofer Montag, 5. Juli 2010 11:12
-
Hallo Mario,
das Access MDB-Dateiformat ist schon ein bißchen komplexer als das von Dbase -
und das vom SQL Server noch ein wenig mehr.Wo man beim Ur-DBase von einer gleichen Satzgröße ausgehen konnte
und über Berechnung (Zeile * Satzbreite) + Dateiheader die jeweilige Zeilen fand,
bemühen die Jet wie der SQL Server Nachschlagealgorithmen (mit unterschiedlicher Komplexität).Aber daran liegt es am Ende kaum. Der wesentliche Unterschied bei .NET DataSets ist,
dass die Daten vollständig im Speicher gehalten werden. Was mehr Ressourcen auf
Programmseite benötigt - und den Speicher sprengen kann, wenn man es ungeschickt anstellt ;-).
Ein Kriterium ist somit Pflicht und ebenso eine Spaltenlistee bei breiten Tabellen,
die nur die Daten abruft die man wirklich anzeigen will.Wobei Du Abfrage-Leistungen deutlich unter 500ms erreichen solltest,
sonst ist vermutlich mehr im Argen.Gruß Elmar
-
Hallo Mario,
Ich hatte angenommen das ich die ACCESS-Tables mit meiner dBase Datenbank vergleichen kann. Da ACCESS die ALLE Daten ja sofort zu verfügung stellt wenn sie geöffnet wird.. Dem scheint ja aber nicht so zu sein. Wenn ich die ACCESS wie eine SQL Tabelle vergleiche dann ist die Performance ok .. muss ich mein Konzept halt doch noch mal ändern, erst den Benutzer zu fragen "welche Daten möchtest du dann sehen" und dann erst mit einer WHERE Bedingung die Ergebnisse liefern. Unter dem Gesichtspunkt ist die ACCESS Tabelle auf unserem künstlich gedrosselten Programmier-Test-Server dann doch sogar ein Tick schneller als der SQL2005...
ehrlich gesagt hab ich nicht verstanden, was Du meinst.
Falls Du vorher sämtliche Daten ausgelesen hast und dann hinterher erst über die WHERE Clause ein zweites Statement, nun mit Filter, abgesetzt hast, könnte ich die üble Performance nachvollziehen. Ansonsten aber nicht.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hallo Stefan,
dBase ist so das beim öffnen der Datei sofort ALLE Daten zur Verfügung stehen.
Da ACCESS beim Doppelklick ebenfalls "augenscheinlich" alle Daten zur Verfügung stellt dachte ich das läuft genauso bei einem SELECT * FROM ...
Aber dem ist nicht so... Ich muss ein leeres Datagrid erst anzeigen und den Benutzer fragen was er sehen will :
Artikelnr. : 4711
Und dann erst einen SELECT * From Artikel WHERE Artikelnr Like = '"+cArtikel+"%'" machen... dann sind die Abfragen schnell genug...
Also ACCESS nicht vergleichen mit dem dBase Verhalten, sondern ACCESS vergleichen mit dem SQL Verhalten...
So meinte ich das... und unter dem Gesichtspunkt sind für zeige alle 300000 Datensäte in voller Breite ( ca. 137 Spalten mit Memofeldern (!)) 11 Sekunden völlig ok...
Wenn ich einen SELECT mache mit einer WHERE Bedingung dann ist es deutlich unter 1 Sekunde...zumindest wenn die Ergebnissmenge nicht mehr als 10000 Daten zurückliefert :) Da ist dann der SQL-Server wieder schneller...
Mir nur etwas schleierhaft der Zusammenhang :
a) ich mach erst eine SQL Abfrage in dem Adapter...
b) dann lese ich alle Daten in ein Dataset mit dem zeitraubenden Fill()
c) und dann fülle ich das Gridview mit dem Dataset
Finde das sehr umständlich irgendwie und dachte das das Gridview direkt mit einer SQL Abfrage zusammenarbeiten kann... so halte ich die Daten doch 3 mal im Speicher...
Auch muss ich mir noch überlegen wer macht die ORDER BY Geschichte... ich kann in allen 3 Varianten im SELECT Statement direkt, im Dataset und dann noch (auch durch den Benutzer ) im Datagrid sortieren...
-
Hallo Mario,
dBase ist so das beim öffnen der Datei sofort ALLE Daten zur Verfügung stehen.
Da ACCESS beim Doppelklick ebenfalls "augenscheinlich" alle Daten zur Verfügung stellt dachte ich das läuft genauso bei einem SELECT * FROM ...
Aber dem ist nicht so... Ich muss ein leeres Datagrid erst anzeigen und den Benutzer fragen was er sehen will :
Artikelnr. : 4711
Und dann erst einen SELECT * From Artikel WHERE Artikelnr Like = '"+cArtikel+"%'" machen... dann sind die Abfragen schnell genug...
Das ist eine der normalen Vorgehensweise, da man nicht unbedingt _alle_ Daten anzeigt und dann dann den User entscheiden lässt, was er sehen will.
In dem Fall wäre eine seitenweise Anzeige über ein Paging sicherlich sinnvoller (alternativ dynamisches Nachladen der Daten)
So meinte ich das... und unter dem Gesichtspunkt sind für zeige alle 300000 Datensäte in voller Breite ( ca. 137 Spalten mit Memofeldern (!)) 11 Sekunden völlig ok...
Mir nur etwas schleierhaft der Zusammenhang :
Punkt "b)" heißt, Du liest alle 300.000 Datensätze ein? Falls ja, selbst schuld :) Es wird ein Schwein auch nur annähernd alle Datensätze brauchen. In deinem Fall kannst Du besser die ersten x Datensätze über ein SQL Statement laden und die weiteren Datensätze auf weitere Seiten verteilen (Paging) bzw. dynamisch nachladen. Filter werden dann über die WHERE Clause gelöst, die die Ergebnisliste einschränkt.a) ich mach erst eine SQL Abfrage in dem Adapter...
b) dann lese ich alle Daten in ein Dataset mit dem zeitraubenden Fill()
c) und dann fülle ich das Gridview mit dem Dataset
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hallo Elmar,
wie Peter Fleischer auch schon angemerkt hat, ist
es beim Arbeiten mit einer Access.mdb nicht
empfehlenswert die Connection für jeden Zugriff
zu öffnen und wieder zu schliessen.
Jedes Öffnen und jedes Schliessen der Verbindung
bedeutet einen schreibenden Zugriff auf die zugehörige *.ldb
und erhöht so die Gefahr einer Beschädigung der *.mdb
bei einem Mehrbenutzerbetrieb.Für das Arbeiten mit Access.mdb kann ich nur empfehlen:
Die benötigte Connection beim erstmaligen Bedarf öffnen,
dabei ConnectionPooling ausschalten (OLE DB Services=-4 im
Connectionstring) und dann bis zum letztmaligen Bedarf
geöffnet lassen. Damit gibt es während der gesamten
Programmlaufzeit einen einzigen Zugriff auf die *.ldb beim
Öffnen und einen weiteren beim Schliessen der Connection.Diese Arbeitsweise hat sich bei mir in vielen Mehrbenutzer-
anwendungen bewährt und vermeidet auch das bei *.mdb
immer wieder beklagte Beschädigen der *.mdb.Hallo Mario,
unter www.gssg.de -> Visual Basic -> VB.net
findest Du die Beispiele-> OLEDB1 (Access.mdb)
-> OLEDB2 (Access.mdb)
und
-> DB CommandObjekte / DataReaderAlle diese Beispiele arbeiten mit einer Access.mdb
und ausgeschaltetem ConnectionPooling.Gruß aus St.Georgen
Peter Götz
www.gssg.de (mit VB-Tipps u. Beispielprogrammen) -
Hallo Peter,
ich will das Thema hier nicht in einem Anfänger-Thread ausarten lassen, zumal es
a) etliche Male anderweitig diskutiert wurde,
b) meine Antwort an Peter Fleischer vom Freitag im Orkus dieses Forums
entschwunden zu sein scheint ;-((Die Problematik der LDB ist mir (als ehemaliger Access MVP, der KB 239114 immer
noch aus dem Stegreif als meistzitierten KB Artikel führt) ebenso bekannt
wie Dir ebenso wie die anfängliche Probleme die das Connection Pooling bei
seiner Einführung insbesondere bei der Jet zeigte.Nur ist das zum einen einige Jahre her: Pooling in the Microsoft Data Access Components
und zumindest das Problem weitgehend ausgestanden - naja, soweit sich bei Microsoft noch
jemand um die Jet 4.0 kümmert (was ich mindestens ebenso bedauere ;-((Und von Haus aus ist das Connection Pooling nicht schädlicher als andere Seiteneffekte.
Denn bei den üblichen Zugriffsmustern von Anwendungen (die man mit der Jet zuverlässig
implementieren kann), führt es zu keinen häufigeren Zugriffen.
Mit "üblichen Zugriffsmustern" bezeichne ich hier, das eine Anwendung kurzzeitig
mehrere Abrufe (zum Beispiel Laden/Aktualisieren von DataSets) durchführt und
danach häufig auch einige Zeit verwaist auf dem Bildschirm ruht - weil ein Sachbearbeiter
was anders wie telefonieren, simmsen, Fußball gucken, etc. macht ;-)In den Fällen findet ein Schließen nach einer Wartezeit statt, nicht aber während
der Aktivitätsphase (siehe Artikel oben - wers nicht glaubt, mag den Process Monitor
der Sysinternals bemühen).Meine Empfehlung beruht am Ende darauf, keine Sonderbehandlung für einen Provider
zu verwenden, da dadurch unterschiedliche Programmiermuster verwendet und
durchgehalten werden müssen (Hier: Mario experimierte mit SQL Server wie Access).
Und ein Connection Pooling für größe Anwendungen (mit SQL Server) unabdingbar wird.Entscheidet man sich ausschließlich für einen Provider, so kann bei ausschließlicher Verwendung
der Jet bzw. auch ACE ein "Tuning" lohnen, bis hin zu dem nur dort möglichen direkten Zugriff
(wenn auch nicht mit OleDb Client Hausmittelchen ;-)Nur es von vorneherein darauf auszulegen, ist einer Portabilität (so man sie jemals haben muß)
nicht gerade förderlich.
Und nun mag sich jeder, die ihm besser gefallene Antwort raussuchen ;-)Gruß Elmar
-
"Elmar Boye" schrieb im Newsbeitrag news:61e1058c-bbd4-4a19-adb1-6072f00b403e...
...
b) meine Antwort an Peter Fleischer vom Freitag im Orkus dieses Forums
entschwunden zu sein scheint ;-((Hi Elmar,
ich kann leider auch Deine Antwort nicht sehen.Die Problematik der LDB ist mir (als ehemaliger Access MVP, der KB 239114 immer
noch aus dem Stegreif als meistzitierten KB Artikel führt) ebenso bekannt
wie Dir ebenso wie die anfängliche Probleme die das Connection Pooling bei
seiner Einführung insbesondere bei der Jet zeigte.Nur ist das zum einen einige Jahre her: Pooling in the Microsoft Data Access Components
und zumindest das Problem weitgehend ausgestanden - naja, soweit sich bei Microsoft noch
jemand um die Jet 4.0 kümmert (was ich mindestens ebenso bedauere ;-((Das Problem ist nicht ausgestanden und ich konnte es problemlos reproduzieren.
Die Theorie zum ConnectionPooling ist klar und es sollte auch funktionieren. Ich konnte es bereits mit 2 Nutzern reproduzieren. Ich habe die mdb im WebService mit etwas länger andauernde Abfragen (z.B. JOIN mit Where-Klassel über einige tausend Datensätze) genutzt. Beim Connection.Open kam nach einiger Zeit "undefinierter Fehler" und der ApplicationPool musste neu gestartet werden, um wieder einen Zugriff zu ermöglichen.
Falls Interesse besteht, kann ich den Test nochmals durchführen.
--
Viele GruessePeter