Toon posts:

C# Connectie met msAccess

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben bezig met het testen van een applicatie die een stagiaire heeft gemaakt. En ik vind de performance niet heel geweldig.
Nu is het programma geschreven in C# en daar heb ik dan niet zoveel ervaring mee. Maar het lijkt dat de slechte performance komt door de manier waarop er met de msAccess database wordt gecommuniceerd.

Eerst zal ik even uitleggen wat de applicatie moet doen.
De applicatie zelf staat locaal, de msAccess database staat op het netwerk.
De app. leest Excel bestanden in, stopt die gegevens in de database en de gebruiker heeft de mogelijkheid om (delen van) de data weer te exporteren naar Excel. Via de applicatie kunnen de database gegevens gelezen en eventueel gewijzigd worden.

De data die er inzit bestaat uit drie delen:
Projecten, percelen en monsters. 1 Project kan meerdere percelen hebben en 1 perceel kan meerdere monsters hebben.

Omdat de stagiaire deze week voor het laatst is en er nog wat andere bugs en features moeten worden opgelost, ben ik dit aan het uitzoeken.

Wat er nu gebeurt is dat als een project wordt geselecteerd, er een connectie wordt gemaakt een select statement wordt gestuurd om de gegevens van dat project op te halen (via een command) vervolgens wordt het command EN de connectie gesloten. Vervolgens wordt een nieuwe connectie gemaakt, worden de bijbehorende percelen opgehaald en wordt weer het command en de connectie gesloten en dan wordt weer een nieuwe connectie geopend en de bijbehorende monsters opgehaald en weer de boel gesloten.

Nu lijkt het mij sneller/beter om de connectie open te houden totdat alle data binnen is en dan pas te sluiten. Volgens de stagiaire kan hij geen tweede command sturen bij een nog geopende connectie.

Ik ben dus gaan zoeken op Google en hier en ik kom heel veel voorbeelden tegen waarin maar 1 statement wordt gestuurd, maar niet waar meerdere statements worden gestuurd met dezelfde connectie.
Kan dit werkelijk niet?

Ik zal mijn vraag verduidelijken met enige code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
   String connectieString = @"Provider=Microsoft.Jet.OLEDB.4.0; Data Source= test.mdb";
   System.Data.OleDb.OleDbConnection conn = new System.Data.OleDb.OleDbConnection(connectieString);
   conn.Open();
   
   String query1 = "SELECT * FROM Project";

   OleDbCommand myCommand1 = new OleDbCommand(query1);
   myCommand1.Connection = conn;
   OleDbDataReader rs1 = myCommand1.ExecuteReader();
   
   while(rs1.Read())
   {
    int projectnr = rs1.GetInt32(rs1.GetOrdinal("projectNr"));
    
    String query2 = "SELECT * FROM Perceel where projectnr=" + projectnr;
    OleDbCommand myCommand2 = new OleDbCommand(query2);
    myCommand2.Connection = conn;   
    OleDbDataReader rs2 = myCommand1.ExecuteReader();
    
    while(rs2.Read())
    {
     int perceelNr = rs2.GetInt32(rs2.GetOrdinal("perceelNr"));

    }
   }


De regel OleDbDataReader rs2 = myCommand1.ExecuteReader(); (regel 18) geeft problemen omdat de connectie open en fetching is.
Wat ik eigen wil is dat OleDbDataReader rs2 = myCommand1.ExecuteReader(); een recordset terug geeft met alle data waarna ik door die recordset kan loopen.
Dat moet toch kunnen? Waarschijnlijk niet met OleDbDataReader maar waar dan wel mee.
Hopelijk heeft iemand hier een antwoord op of kan iemand mij in de juste richting sturen.
Alvast bedankt. _/-\o_

  • whoami
  • Registratie: December 2000
  • Laatst online: 30-04 15:31
Als je meerdere statements na elkaar stuurt, dan gebruik je gewoon dezelfde connectie (en hou je dus die connectie open, tot wanneer je voor een (onbepaalde) tijd geen DB access meer hoeft te doen:

Als je niet met een DataReader wilt werken, dan kan je mbhv een Data-Adapter een DataTable object gaan vullen. (Een DataSet bestaat uit datatables; een dataset is een 'disconnected' view op die data).

https://fgheysels.github.io/


  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Bij mijn weten heeft een open DataReader exclusief toegang tot zijn Connection-object; er kunnen dan geen andere Commands door worden gestuurd. Dus dat kan echt niet, dat klopt.

Wat je evt. wel zou kunnen doen is in plaats van de twee queries nesten ze sequentieel maken door eerst alle projectnummers op te halen en even in een lijst te zetten. Dan kan je je eerste Command-object sluiten en vervolgens per projectnummer al je percelen ophalen in een loop. Zo heb je maar 1 Command-object nodig die open is (en dus ook maar 1 connection)

[ Voor 4% gewijzigd door MrBucket op 14-09-2005 12:56 ]


Verwijderd

Overigens wil ik je verwachtingen wel temperen. Access biedt met multi-user gebruik op een netwerkshare onvermijdelijk slechte performance, onafhankelijk van hoe je deze database benadert. Verwacht dus geen wonderen.

Het is daarom ook relevant om uit te zoeken wanneer / waar er performance-problemen zijn en of die inderdaad aan de code liggen, want wellicht zijn de problemen puur gerelateerd aan de database zelf.

Verder is het prima mogelijk om meerdere commands aan een connectie te koppelen en daarop een .ExecuteReader() op uit te voeren. Je kan echter niet een connectie gebruiken waarop een open datareader staat, dus je zult de vorige datareader eerst leeg moeten consumeren en sluiten voordat je een nieuwe datareader vult. Je kan een dataset gebruiken, maar dat kan zowel performance-voordelen als -nadelen opleveren, dus lees je eerst goed in de materie in voordat je hierover beslissingen neemt.

Als ik naar je code kijkt gebeurt er daar wel iets heel inefficients. Je kan namelijk veel beter de data in de Project en Perceel tabel in 1 query ophalen m.b.v een JOIN, zie bijv. http://www.w3schools.com/sql/sql_join.asp. In dat geval heb je voor dit stukje code maar 1 datareader nodig en krijg je bovenstaand probleem niet.

Succes :)

Verwijderd

Topicstarter
Ik heb naar de data-set gekeken zoals whoami voorstelt en die is best ingewikkeld en uitgebreidt.
We hadden de mogelijkheid om de data tijdelijk op te slaan in een array overwogen, maar ik wilde eerst zien of het niet anders kon. De mogelijkheid van de data in 1 keer ophalen via een join is ook niet echt een optie omdat in het echt de appl. nog wel wat ingewikkelder is.

Wat we gaan doen is het volgende.
We open een connectie
Gebruiken dataReader om de data in een array te bewaren.
Sluiten dataReader
Halen andere gegevens op mbv de daraReader MET dezelfde connectie.
Zetten het weer in een array
Sluiten dataReader
enz.

Ik dacht (hoopte) dat C# een gelijksoortig object had als VB6 of PHP waarmee ik eenvoudig een recordset kan krijgen van mijn query. Als ik het goed begrijp, kan dat dus niet.
Jammer ;)

Bedankt voor jullie hulp.

Verwijderd

Verwijderd schreef op woensdag 14 september 2005 @ 13:59:
Ik heb naar de data-set gekeken zoals whoami voorstelt en die is best ingewikkeld en uitgebreidt.
We hadden de mogelijkheid om de data tijdelijk op te slaan in een array overwogen, maar ik wilde eerst zien of het niet anders kon. De mogelijkheid van de data in 1 keer ophalen via een join is ook niet echt een optie omdat in het echt de appl. nog wel wat ingewikkelder is.

Wat we gaan doen is het volgende.
We open een connectie
Gebruiken dataReader om de data in een array te bewaren.
Sluiten dataReader
Halen andere gegevens op mbv de daraReader MET dezelfde connectie.
Zetten het weer in een array
Sluiten dataReader
enz.

Ik dacht (hoopte) dat C# een gelijksoortig object had als VB6 of PHP waarmee ik eenvoudig een recordset kan krijgen van mijn query. Als ik het goed begrijp, kan dat dus niet.
Jammer ;)

Bedankt voor jullie hulp.
Datasets zijn juist precies wat je wil gebruiken als ik jouw verhaal zo lees, en jullie zijn nu bezig om met die arrays eigenlijk hetzelfde te doen. Ja, het is uitgebreid en ingewikkeld in het begin, maar wel krachtig, waardoor je heel declaratief te werk kan gaan en minder code hoeft te schrijven. Als ik jou was zou ik er toch eens mee gaan spelen om die kracht te ontdekken.

Mbt joins: ik ben heel erg benieuwd wat het gebruik van joins tegenhoudt. Er zijn wel dingen die niet mogelijk zijn om in 1 query op te lossen, maar het overgrote deel van de bestaande problemen juist wel.

Verwijderd

Topicstarter
We zijn eerst begonnen met een join (over 5 tabellen) en left joins maar dat duurde helemaal erg lang. Zeer waarschijnlijk omdat we met msAccess werken.
De traagheid zat vooral in de leftjoin. We hadden alle kolomen nodig ook als er nog geen waarde in zat. Het resultaat was dan ook enorm groot.
Daarom hebben we besloten om het op te splitsen in 4 losse queries, zodat het sneller zou gaan. Alleen de oplossing die de stagiaire had bedacht om elke keer een nieuwe connectie te openen was nog erg langzaam.
Hij is nu zijn code aan het ombouwen naar de connectie ophouden zolang die nodig is en de tussenstappen bewaren in arrays.
Als dat klaar is gaan we weer de performance testen en hopelijk is die dan beter.

Verder heb je helemaal gelijk dat door msAccess te gebruiken we het ook wel een beetje op ons afroepen ;)
Daarom is de applicatie voorbereid op een echte databaseserver zoals ms sql of mySQL, maar zolang die nog niet up-and-running is moeten we het met access doen.

  • whoami
  • Registratie: December 2000
  • Laatst online: 30-04 15:31
Heb je wel indexen op die access db ?

https://fgheysels.github.io/

Pagina: 1