[Delphi] Database overschrijven

Pagina: 1
Acties:

  • Oscar Mopperkont
  • Registratie: Februari 2001
  • Laatst online: 03-08-2024
Ik heb een progje geschreven dat zijn informatie opslaat in een Database. In het filemenu heb ik dus ook "Opslaan als..." staan. Als de gebruiker dan een bestand selecteert dat al bestaat dan krijg hij de vraag of deze overschreven moet worden. Vervolgens wordt het bestand gedelete en maakt het programma gewoon een nieuw bestand aan met die bestandsnaam.

Dat werkt alleen de eerste keer goed. Als ik het daarna nog een keer doe en het bestand weer wil overschrijven dan wordt de file eerst netjes gedelete, maar toch krijg ik van de TAdoxCatalog de foutmelding dat de database al bestaat. In de help van Delphi staat niks over de TAdoxCatalog (waarom weet ik niet, maar goed) ik kan dus niet ontdekken waarom het fout gaat.

De code is als volgt:
Delphi:
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
26
27
28
29
30
procedure TfrFormulier.OpslaanAlsClick(Sender: TObject);
var
  DataSource,dbName,cs : string;
  i:        integer;
  aStream:  TStringStream;
const
  S_EMPTY = '';
begin
  //create DB
  SaveDialog1.DefaultExt:='mdb';
  SaveDialog1.Filter:='(mdb, *.mdb)|*.mdb;';

  if (SaveDialog1.Execute) then 
  begin
    if FileExists(SaveDialog1.FileName) then
      if (MessageDlg('Bestand bestaat al, overschrijven?', mtConfirmation,[mbYes,
          mbNo], 0) = mrYes) then
        DeleteFile(SaveDialog1.FileName)
      else
        Abort;

    dbName:=SaveDialog1.FileName;
    DataSource :=
      'Provider=Microsoft.Jet.OLEDB.4.0' +
      ';Data Source=' + dbName +
      ';Jet OLEDB:Engine Type=5';


    ADOXCatalog1.Create1(DataSource);
...

Op "ADOXCatalog1.Create1(DataSource);" loopt hij dus vast als ik het de tweede keer doe. Ik heb het idee dat het er mee te maken heeft dat hij bij de tweede keer zelf het bestand heeft aangemaakt. Dus dat ie dat nog weet. Maar hoe verander ik dat?

[ Voor 6% gewijzigd door Oscar Mopperkont op 21-01-2005 11:30 ]


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 11:29

Creepy

Tactical Espionage Splatterer

En je hebt (uiteraard?) je connectie naar die DB / Datasource netjes gesloten?

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • Oscar Mopperkont
  • Registratie: Februari 2001
  • Laatst online: 03-08-2024
Creepy schreef op vrijdag 21 januari 2005 @ 11:51:
En je hebt (uiteraard?) je connectie naar die DB / Datasource netjes gesloten?
Wel de Tables, maar welk commando moet ik daarvoor gebruiken? Daar er een heleboel in aanmerking (lijken) te komen. In ieder geval voor mij :)

Ik kan het serieus niet vinden. Moet ik dan alleen iets doen met de TAdoxCatalog, of alleen met de TAdoconnection, of met een combinatie van beide?

[ Voor 19% gewijzigd door Oscar Mopperkont op 21-01-2005 13:44 ]


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 10:01

Tomatoman

Fulltime prutser

Oscar Mopperkont schreef op vrijdag 21 januari 2005 @ 12:14:
[...]

Wel de Tables, maar welk commando moet ik daarvoor gebruiken? Daar er een heleboel in aanmerking (lijken) te komen. In ieder geval voor mij :)

Ik kan het serieus niet vinden. Moet ik dan alleen iets doen met de TAdoxCatalog, of alleen met de TAdoconnection, of met een combinatie van beide?
Wat dacht je van MijnADOConnection.Close? Dat had je trouwens ook kunnen uitvinden door het even te proberen.

Een goede grap mag vrienden kosten.


  • Oscar Mopperkont
  • Registratie: Februari 2001
  • Laatst online: 03-08-2024
tomatoman schreef op vrijdag 21 januari 2005 @ 16:10:
[...]
Wat dacht je van MijnADOConnection.Close? Dat had je trouwens ook kunnen uitvinden door het even te proberen.
Geprobeerd (als eerste), maar werkt niet. Vandaar dat ik ook zei dat ik het niet kan vinden.

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 10:01

Tomatoman

Fulltime prutser

Dat is vervelend. Door de databaseverbinding dicht te gooien zou de databaseserver (Access) het bestand moeten sluiten. Het kan echter zijn dat er nog een andere sessie actief is die de database openhoudt, bijvoorbeeld het programma dat je design-time in de IDE gebruikt. Een andere mogelijkheid is dat de server wat tijd nodig heeft om het bestand daadwerkelijk te sluiten. In dat geval kan het helpen om het een seconde later opnieuw te proberen.

Ik heb een keer een unit geschreven met wat functies die je kunnen helpen. Je kunt hem hier downloaden.

Een goede grap mag vrienden kosten.


  • Oscar Mopperkont
  • Registratie: Februari 2001
  • Laatst online: 03-08-2024
De database wordt inderdaad opengehouden, ik kan hem namelijk ook niet deleten als ik gewoon de explorer/verkenner van windows gebruik. hij zegt dan dat het bestand niet verwijderd kan worden omdat het bestand gebruikt wordt door een ander programma.

Overigens is dit de gehele procedure:
Delphi:
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
procedure TfrFormulier.OpslaanAlsClick(Sender: TObject);
var
  DataSource,dbName,cs : string;
  i:        integer;
  aStream:  TStringStream;
const
  S_EMPTY = '';
begin
  //create DB
  SaveDialog1.DefaultExt:='mdb';
  SaveDialog1.Filter:='(mdb, *.mdb)|*.mdb;';

  if (SaveDialog1.Execute) then 
  begin
    if FileExists(SaveDialog1.FileName) then
      if (MessageDlg('Bestand bestaat al, overschrijven?', mtConfirmation,
[mbYes, mbNo], 0) = mrYes) then
        DeleteFile(SaveDialog1.FileName)
      else
        Abort;

    dbName:=SaveDialog1.FileName;
    DataSource :=
      'Provider=Microsoft.Jet.OLEDB.4.0' +
      ';Data Source=' + dbName +
      ';Jet OLEDB:Engine Type=5';

    ADOXCatalog1.Create1(DataSource);

    //connect DB
    ADOConnection1.ConnectionString := DataSource;
    ADOConnection1.LoginPrompt := False;
    ADOCommand1.Connection := ADOConnection1;

    //add tables
    cs:='CREATE TABLE Instellingen (' +
      'Groepen NUMERIC,' +
      'Criteria NUMERIC)';
    ADOCommand1.CommandText := cs;
    ADOCommand1.Execute;

    cs:='CREATE TABLE Criteria (' +
      'Criteria TEXT(100))';
    ADOCommand1.CommandText := cs;
    ADOCommand1.Execute;

    cs:='CREATE TABLE OpmerkingenCijfers (' +
      'Opmerkingen MEMO,' +
      'Cijfers TEXT(1))';
    ADOCommand1.CommandText := cs;
    ADOCommand1.Execute;

    cs:='CREATE TABLE Standaardzinnen (' +
    'Zinnen MEMO)';
    ADOCommand1.CommandText := cs;
    ADOCommand1.Execute;

    cs:='CREATE TABLE AanhefAfsluiting (' +
    'AanhefAfsluiting MEMO)';
    ADOCommand1.CommandText := cs;
    ADOCommand1.Execute;



    ADOTable1.Close;

    ADOTable1.ConnectionString:=DataSource;
    ADOTable1.TableName:='Instellingen';
    ADOTable1.Active:=True;
    with AdoTable1 do
    begin
      Insert;
      FieldByName('Groepen').Value := AantalGroepen;
      FieldByName('Criteria').Value := AantalCriteria;
      post;
    end;

    ADOTable1.Close;

    ADOTable1.ConnectionString:=DataSource;
    ADOTable1.TableName:='Criteria';
    ADOTable1.Active:=True;
    for i:=0 to clEdits.Count-1 do
    begin
      with AdoTable1 do
      begin
        Insert;
        FieldByName('Criteria').Value := TEdit(clEdits[i]).Text;
        post;
      end;
    end;

    ADOTable1.Close;

    ADOTable1.ConnectionString:=DataSource;
    ADOTable1.TableName:='Standaardzinnen';
    ADOTable1.Active:=True;
    ADOTable1.Insert;
    ADOTable1.FieldByName('Zinnen').Value := edtScore5.Text;
    ADOTable1.post;
    ADOTable1.Insert;
    ADOTable1.FieldByName('Zinnen').Value := edtScore4.Text;
    ADOTable1.post;
    ADOTable1.Insert;
    ADOTable1.FieldByName('Zinnen').Value := edtScore3.Text;
    ADOTable1.post;
    ADOTable1.Insert;
    ADOTable1.FieldByName('Zinnen').Value := edtScore2.Text;
    ADOTable1.post;
    ADOTable1.Insert;
    ADOTable1.FieldByName('Zinnen').Value := edtScore1.Text;
    ADOTable1.post;
    ADOTable1.Insert;
    ADOTable1.FieldByName('Zinnen').Value := edtHoger.Text;
    ADOTable1.post;
    ADOTable1.Insert;
    ADOTable1.FieldByName('Zinnen').Value := edtGemiddeld.Text;
    ADOTable1.post;
    ADOTable1.Insert;
    ADOTable1.FieldByName('Zinnen').Value := edtLager.Text;
    ADOTable1.post;

    ADOTable1.Close;

    ADOTable1.ConnectionString:=DataSource;
    ADOTable1.TableName:='AanhefAfsluiting';
    ADOTable1.Active:=True;
    aStream := TStringStream.Create( S_EMPTY );
    rchAanhef.PlainText:=false;
    rchAanhef.Lines.SaveToStream(aStream);
    ADOTable1.Insert;
    ADOTable1.FieldByName('AanhefAfsluiting').Value := aStream.DataString;
    ADOTable1.post;
    aStream := TStringStream.Create( S_EMPTY );
    rchAfsluiting.PlainText:=false;
    rchAfsluiting.Lines.SaveToStream(aStream);
    ADOTable1.Insert;
    ADOTable1.FieldByName('AanhefAfsluiting').Value := aStream.DataString;
    ADOTable1.post;

    ADOTable1.Close;
    ADOTable1.ConnectionString:=DataSource;
    ADOTable1.TableName:='OpmerkingenCijfers';
    ADOTable1.Active:=True;
    for i:=0 to clRichEdits.Count-1 do
    begin
      aStream := TStringStream.Create( S_EMPTY ) ;
      TRichEdit(clRichEdits[i]).PlainText:=false;
      TRichEdit(clRichEdits[i]).Lines.SaveToStream(aStream);

      with AdoTable1 do
      begin
        Insert;
        FieldByName('Opmerkingen').Value := aStream.DataString;
        FieldByName('Cijfers').Value:= TComboBox(clComboBoxen[i]).Text;
        post;
      end;
    end;
    ADOTable1.Close;
    ADOConnection1.Connected:=false;
    ADOConnection1.close;
    ADOCommand1.Connection := ADOConnection1;
    ADOCommand1.Connection.Connected:=false;
    ADOCommand1.Connection.Close;
  end;


end;

Op het einde staan momenteel allemaal pogingen om de boel te sluiten, maar dat lukt dus kennelijk niet.
Verder is dit de enige procedure die ik nu gebruik om te verbinden met de database. Er is ook nog een "open" procedure, maar die roep ik nu niet aan met het testen, dus daar ligt de fout niet. Het moet echt in deze procedure zitten.

[ Voor 98% gewijzigd door Oscar Mopperkont op 23-01-2005 15:28 ]


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 10:01

Tomatoman

Fulltime prutser

Aan jou de taak uit te vinden welk programma het bestand openhoudt. Ik gok dat je de fout bij jezelf moet zoeken. Als de het bestand open is als jou programma draait en gesloten wordt zodra jouw programma afsluit, weet je dat je dat je aan het debuggen moet slaan.

Een goede grap mag vrienden kosten.


  • Oscar Mopperkont
  • Registratie: Februari 2001
  • Laatst online: 03-08-2024
tomatoman schreef op zondag 23 januari 2005 @ 15:31:
Aan jou de taak uit te vinden welk programma het bestand openhoudt. Ik gok dat je de fout bij jezelf moet zoeken. Als de het bestand open is als jou programma draait en gesloten wordt zodra jouw programma afsluit, weet je dat je dat je aan het debuggen moet slaan.
Mijn programma houdt het bestand open, als ik hem afsluit dan kan ik hem gewoon deleten. Dus de fout ligt zeker bij mij en wel in die procedure. Alleen weet ik om eerlijk te zijn niet waar ik moet beginnen met het debuggen van dit probleem. Ik heb namelijk geen idee hoe je de verbinding verbreekt (ik dacht dat het MijnAdoConnection.close zou moeten zijn), maar de commando's die ik probeer verbreken kennelijk de verbinding niet, maar geven ook geen foutmeldingen.

Is er geen algemeen commanod dat alle verbindingen met de database kan dichtgooien?

[ Voor 6% gewijzigd door Oscar Mopperkont op 23-01-2005 15:51 ]


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 10:01

Tomatoman

Fulltime prutser

Nu je je eerdere post hebt gewijzigd zie ik waar het probleem ligt. Je hoort een TADOConnection te gebruiken om de toegang tot de database te centraliseren. Wat je echter doet is dat iedere TADOTable afzonderlijk verbinding maakt met de database. Als je bij TADOTable de ConnectionString property instelt in plaats van de Connection property, creërt die TADOTable achter de schermen zijn eigen TADOConnection component. Daardoor krijg je een heleboel connecties met de database, die je allemaal expliciet zult moeten sluiten om de database vrij te geven.

Als je vijf TADOTables gebruikt die allemaal zelf een databaseverbinding opbouwen en ook nog een TADOConnection die de verbinding opbouwt, heb je effectief zes databaseverbindingen gemaakt. Dat geeft een hoop overhead en is ook niet goed. Je hebt juist een TADOConnection om alle toegang tot de database te centraliseren. Maak bij alle databasecomponenten zoals TADOTable de ConnectionString property leeg en verbind ze in plaats daarvan met één TADOConnection component. Nu kun je de verbinding in één keer sluiten door ADOConnection.Active op false te zetten of ADOConnection.Close aan te roepen. Dan wordt die ene verbinding gesloten en worden alle gekoppelde componenten - inclusief alle TADOTables - inactief gemaakt.

Een goede grap mag vrienden kosten.


  • Oscar Mopperkont
  • Registratie: Februari 2001
  • Laatst online: 03-08-2024
Ik heb nu de alle
Delphi:
1
ADOTable1.ConnectionString:=DataSource;

Weggehaald en ik heb dit vervangen door één commando:
Delphi:
1
ADOTable1.Connection:=ADOConnection1;

Vervolgens eindig ik met:
Delphi:
1
2
3
4
    ADOTable1.Close;
    ADOTable1.Connection.Close;
    ADOConnection1.Connected:=false;
    ADOConnection1.close;

Maar helaas werkt dit ook nog niet.

Update
Ik eindig nu met de volgende commando's
Delphi:
1
2
3
4
5
6
7
    ADOTable1.Close;
    ADOTable1.Connection.Close;
    ADOConnection1.Connected:=false;
    ADOConnection1.close;
    ADOCommand1.Connection.Connected:=false;
    ADOCommand1.Connection.Close;
    ADOXCatalog1.Disconnect;

En nu werkt het dus wel! Thnx TomatoMan :)

[ Voor 31% gewijzigd door Oscar Mopperkont op 23-01-2005 16:38 ]


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 10:01

Tomatoman

Fulltime prutser

Heb je via de Object Inspector misschien nog ergens anders een paar ConnectionString properties ingevuld?
Oscar Mopperkont schreef op zondag 23 januari 2005 @ 15:23:
Overigens is dit de gehele procedure:

[norml][[/]code]
Nu we toch bezig zijn met verbeteringen :) :
Regel 22-61: je definieert in de database geen indexen en geen relaties tussen de afzonderlijke tabellen. Is dat met opzet gedaan?

Regel 65: kan weg, want als de database nog niet open is kan de tabel ook niet open zijn.

Regel 67-78 en 80-93: dit is een rare constructie. Je hergebruikt nu je ADOTable1 door de tabelnaam te wijzigen. Dat maakt je code nogal foutgevoelig, want de kans is groot dat als je heel ergens andes in je programma ADOTable1 gebruikt, je per ongeluk met de verkeerde tabel gaat klooien. Beter kun je daarom ADOTable1 runtime creëren aan het begin van de procedure, hem dan gebruiken om de tabellen te bewerken en hem aan het einde van de procedure in een try-finally constructie weer vernietigen. Hetzelfde geldt voor ADOCommand1.

Regel 70-76, 98-100, enzovoort: AppendRecord(...) is je vriend :)

[ Voor 5% gewijzigd door Tomatoman op 23-01-2005 16:39 ]

Een goede grap mag vrienden kosten.


  • Oscar Mopperkont
  • Registratie: Februari 2001
  • Laatst online: 03-08-2024
Het werkt nu (dus ik ben blij), nogmaal bedankt Tomatoman _/-\o_

Maar ff antwoord op je vragen:
tomatoman schreef op zondag 23 januari 2005 @ 16:37:
Nu we toch bezig zijn met verbeteringen :) :
Regel 22-61: je definieert in de database geen indexen en geen relaties tussen de afzonderlijke tabellen. Is dat met opzet gedaan?
Ik gebruik de database omdat het zo'n beetje de enige manier is (die ik nog een beetje beheers) om de boel op te slaan. Er hoeven geen relaties te zijn tussen de tabellen. Waarschijnlijk maak ik onnodig veel tabellen aan, maar het werkt dus ja.
Regel 65: kan weg, want als de database nog niet open is kan de tabel ook niet open zijn.
Zal ik doen
Regel 67-78 en 80-93: dit is een rare constructie. Je hergebruikt nu je ADOTable1 door de tabelnaam te wijzigen. Dat maakt je code nogal foutgevoelig, want de kans is groot dat als je heel ergens andes in je programma ADOTable1 gebruikt, je per ongeluk met de verkeerde tabel gaat klooien. Beter kun je daarom ADOTable1 runtime creëren aan het begin van de procedure, hem dan gebruiken om de tabellen te bewerken en hem aan het einde van de procedure in een try-finally constructie weer vernietigen. Hetzelfde geldt voor ADOCommand1.
Als ik wat tijd vrij heb zal ik het op die manier proberen te doen. Voorlopig loop ik nog nergens tegenaan. Behalve dan dat ik bij de openprocedure ook zal moeten aanpassen dat de verbinding gesloten wordt.
Regel 70-76, 98-100, enzovoort: AppendRecord(...) is je vriend :)
AppendRecord? Ook daar zal ik nog eens naar kijken.

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 10:01

Tomatoman

Fulltime prutser

Typfoutje: ik bedoelde AppendRecord :o. De opmerkingen zijn trouwens verbeteringen, het zijn geen van alle bugs. Hier nog een laatste: in regel 43-44 definieer je een tabel Criteria met daarin een veld dat precies dezelfde naam heeft. Dat kan gewoon en zou geen fouten moeten geven. Toch is het vaak handiger om de namen verschillend te kiezen, omdat het in bepaalde gevallen tot cryptische foutmeldingen in query's kan leiden (bijvoorbeeld omdat de veldnaam voor een tabelnaam wordt aangezien). Veel gebruikers hebben dergelijke problemen gehad, waarbij de fout werd veroorzaakt door bugs in slecht geschreven database engines of third-party componenten. Succes!

[ Voor 69% gewijzigd door Tomatoman op 23-01-2005 16:58 ]

Een goede grap mag vrienden kosten.


  • Oscar Mopperkont
  • Registratie: Februari 2001
  • Laatst online: 03-08-2024
Je schreef ook AppendRecord, ik maakte de typfout ;)

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 10:01

Tomatoman

Fulltime prutser

Oscar Mopperkont schreef op zondag 23 januari 2005 @ 16:24:
Update
Ik eindig nu met de volgende commando's
Delphi:
1
2
3
4
5
6
7
    ADOTable1.Close;
    ADOTable1.Connection.Close;
    ADOConnection1.Connected:=false;
    ADOConnection1.close;
    ADOCommand1.Connection.Connected:=false;
    ADOCommand1.Connection.Close;
    ADOXCatalog1.Disconnect;

En nu werkt het dus wel! Thnx TomatoMan :)
TADOXCatalog of IADOXCatalog ken ik niet, dus daar kan ik niets over zeggen. Voor de rest: aangezien ADOTable1 en ADOCommand1 aan ADOConnection1 hangen, kan het veel simpeler:
Delphi:
1
2
ADOConnection1.Connected := False; // of ADOConnection1.Close;
ADOXCatalog1.Disconnect; // ik weet niet in hoeverre deze regel nodig is
Met het sluiten van ADOConnection1 worden ADOTable1 en ADOCommand1 automatisch inactief gemaakt (oftewel ADOTable1.Active := False et cetera).

Een goede grap mag vrienden kosten.

Pagina: 1