Italian community of Lazarus and Free Pascal

Programmazione => Databases => Topic aperto da: Carlo Bergamini - Novembre 15, 2015, 01:38:44 pm

Titolo: Sqlite e Zeos Table
Inserito da: Carlo Bergamini - Novembre 15, 2015, 01:38:44 pm
Buon pranzo se avete ancora questa brutta abitudine  :D

Mi sto picchiando con qualcosa che reputo banale ma che non mi funziona.
Le mie precedenti esperienze con i db risalgono soprattutto ai tempi di VB6 ed usavo principalmente MSSql come engine. Lavoravo principamente da codice senza componenti "bandati". Ho lavoarto anche con Delphi ( alla versione 6) ma per un progetto in cui fornivo accesso a VB tramite dll a FlexCompress di ComponentAce. Bell'oggetto.

Ora, per un piccolo progetto di interfaccia a centralino via seriale, sto usando Lazarus.
MI piace molto l'ambiente, veramente notevole.
Sempre per la prima volta, sto usando sqlite come db.

Ho esigenze veramente minimali, avrei potuto risolvere anche con un file tipo ini per persistere le configurazioni del centralino. Mi piace però l'idea di sperimentare le cose che non conosco e cosi...

Dopo lo sproloquio vengo al punto.
1 oggetto TZConnection ( impostazioni da codice), no designtme, autocommit false.
2 oggetti TzTable con le stesse proprietà riguardo a cache ect.
Nella seconda tabella ho un errore 'library routine called out of sequence' nel tentativo di inserire più di 1 record.

Cercando in giro sembra che il problema, negli altri casi, sia dovuto a impostazione errate della connessione. Nel mio caso direi di no perché la prima tabella lavora normalmente, ma esegue sempre e solo inserimento di 1 record alla volta.

Il codice riportato sotto dovrebbe essere eseguito 10 volte. Il primo inserimento funziona, al secondo becco l'eccezione.
Codice: [Seleziona]
procedure TfrmMain.CreateConfig(chnList: HBChanList; confNum: Integer);
var
  i: Integer;
  s: String;
begin
  with tblConfigurazioni do begin
    if not Active then Open;
  Insert;
  FieldByName('CodImpianto').Value := txtCode.Text;
  FieldByName('NumMemoria').Value := confNum;
      FieldByName('DataCreazione').Value := Now;
for i := Low(chnList) to High(chnList) do begin
  if i < 9 then s := '0' + IntToStr(i + 1) else s := IntToStr(i + 1);
FieldByName('Can_' + s).Value := chnList[i];
end;
ApplyUpdates;
    //CommitUpdates;
    end;
end;

Credo che il problema sia da inputare all'uso errato che di ApplyUpdates ed Insert.
Qual'è il modo corretto di chiamare questi metodi, ovvero in quale sequenza?

Grazie e buona domenica.

Carlo
Titolo: Re:Sqlite e Zeos Table
Inserito da: nomorelogic - Novembre 16, 2015, 03:19:15 pm
Solitamente ad una "Insert" (che mette il clientdataset in modalità dsInsert) deve corrispondere un "Post" quando si è finito di lavorare sul record corrente (o in alternativa un "Cancel" se si vogliono abbandonare le modifiche al record corrente).
Sia Post che Cancel riportano il dataset in modalità dsBrowse e *solo quando si è in dsBrowse* si può chiamare "ApplyUpdates". Questo perché ApplyUpdates manda al server (sotto forma di istruzioni DML/SQL) le modifiche che sono in cache presso il clientdataset.

Nel tuo codice vedo una Insert, un ApplyUpdates ma nessuna Post...
Devi quindi mettere la Post che fa tornare il clientdataset in modalità dsBrowse e poi chiamare ApplyUpdates.
Titolo: Re:Sqlite e Zeos Table
Inserito da: Carlo Bergamini - Novembre 16, 2015, 10:30:46 pm
Devo provare quello che mi hai scritto, e non perché non ti creda ovviamente.
Ieri, dopo un certo numero di tentativi infruttuosi, ho testato quello che volevo realizzare con un progettino ad hoc: 4 campi in croce ed uno spinbutton per settare il numero di record da scrivere. Più ovviamente button per apertura connesione, chiusura ect.

Ha funzionato alla prima e senza problemi. Non capendo il perché ho guardato con più attenzione la struttura della tabella. La differenza sostanziale è nel fatto che dove non funziona ho un default per i campi integer, cioè assegna 9. Se rimuovo questo constraint dalla tabella funziona anche nel mio modo scorretto. Ora la domanda è:
come si inserisce un record in questa tabella con un default? Ovvero in realtà, come se se possono inserire 10 in sequenza? Il problema nasce dal fatto che io sovrascrivo una parte dei default? Il deafult non dovrebbe intervenire solo nel caso in cui io non assegni un valore?

Come al solito più dubbi che certezze  :(



 
Titolo: Re:Sqlite e Zeos Table
Inserito da: Stilgar - Novembre 24, 2015, 03:42:14 pm
Ciao Carlo.
Per i Default, prova ad usare i NULL.
Cerca nel TField come impostare il campo a null (dovrebbe essere qualche cosa del tipo setNull(true/false) )

Stilgar
Titolo: Re:Sqlite e Zeos Table
Inserito da: Carlo Bergamini - Novembre 24, 2015, 09:12:20 pm
Grazie Naib, tutto bene tra i Fremen dell'alto deserto?  :D

A parte quel problema, che ho accantonato, ne è sorto un altro davvero simpatico.
So che sqlite tratta i tipi di campo con una certa libertà, ma questo mi sembra un po troppo.

Nella tabella ho un campo CodImpianto dichiarata come string di lunghezza 20.
Per la codifica uso banalmente una conversione in esadecimale della data e dell'ora.

Con un valore tipo: 24E54337D7 mi va in errore runtime di overflow di floating point!!!
Ma chi caspita lo ha autorizzato a cercare di convertire una stringa in un numero a virgola mobile?
Ho dovuto anteporre una lettera per evitare il problema.

Bello sqlite, ma in futuro me ne terrò alla larga.

Carlo.
Titolo: Re:Sqlite e Zeos Table
Inserito da: Carlo Bergamini - Novembre 25, 2015, 09:30:31 am
Stamani, a mente fresca, ho voluto rileggere con più attenzione le note di sqlite sui suoi datatypes.

Dopo di che ho modificato la definizione del campo CodImpianto da String 20 a Text.
Ora in inserimento non genera più eccezione floating point overflow.
In lettura però, attribuendo il valore letto a una label, vedo a video la scritta 'memo' ( apici messi per chiarezza ).

Leggo il valore con questo codice:
Codice: [Seleziona]
lblCode.Caption := tblImpianti.FieldByName('CodImpianto').Text

Per correggere questo aspetto ho modificato nel modo seguente:
Codice: [Seleziona]
lblCode.Caption := String(tblImpianti.FieldByName('CodImpianto').Value);

Per onestà intellettuale, e visto che era mia ignoranza, penso sia giusto rettificare la mia precedente affermazione su sqlite.

Carlo.