Entwickler-Ecke

Datenbanken - TSQLDataSet - Datensatz finden und Updaten


NOS1971 - Sa 12.07.14 16:43
Titel: TSQLDataSet - Datensatz finden und Updaten
Hallo zusammen,

irgendwie bekomme ich es nicht hin in dem ersten gefundenen Datensatz in einem SQLDataSet 2 Werte zu ändern und zu Posten.

Was mache ich falsch? .. ich bekomme immer den Fehler das der Datensatz nicht im richtigen Mode geöffnet sei. CurrentAddDataItem ist ein TSQLDataSet udn ich nutze SQLite3.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
     
      CurrentAddItem.CommandText := 'SELECT * FROM ResultURLTable WHERE URL = "' + tempurlstring + '";';
      CurrentAddItem.Open;
      if not CurrentAddItem.IsEmpty then
      begin
       // item found
       CurrentAddItem.First;

       TempParentSitesString := TField(CurrentAddItem.FieldByName('PARENTSITESLIST')).AsString + CurrentURL + sLinkSeperator;
       TempCurrentReferingLinks := TField(CurrentAddItem.FieldByName('REFERINGLINKS')).AsInteger + 1;
       CurrentAddItem.Edit;

       TField(CurrentAddItem.FieldByName('REFERINGLINKS')).AsInteger := TempCurrentReferingLinks;
       TField(CurrentAddItem.FieldByName('PARENTSITESLIST')).AsString := TempParentSitesString;
       CurrentAddItem.Post;

       CurrentAddItem.Close;


Ich hoffe ihr könnt mir helfen.

Grüße,

Andreas


Delete - Sa 12.07.14 17:53

Könnte ja eventuell daran liegen daß TSQLDataSet [http://docwiki.embarcadero.com/Libraries/XE5/de/Data.SqlExpr.TSQLDataSet] eine unidirektionale Datenmenge ist und du daher nur mit SQL-Befehlen arbeiten kannst statt wie in deinem Beispiel mit Edit und Post:

Im Gegensatz zu herkömmlichen Datenmengen puffern unidirektionale Datenmengen keine Datensätze. Aus diesem Grund stehen für die Navigation nur die Methoden First und Next zur Verfügung. Es gibt keine integrierte Datenbearbeitung: Sie können die Daten einer SQL-Datenmenge nur bearbeiten, indem Sie explizit eine SQL-UPDATE-Anweisung verwenden oder die Datenmenge über einen Provider mit einer Client-Datenmenge verbinden. Funktionen, bei denen mehrere Datensätze in einem Puffer abgelegt werden müssen (z.B. Filter oder Lookup-Felder), werden nicht unterstützt.


NOS1971 - Sa 12.07.14 18:01

Shit ... das wusste ich nicht und habe ich auch bei der suche nach antworten überlesen ... gibt es denn eine variante einer compo mit der ich zunächst einen datensatz suche und diesen auch direkt ändern kann denn die variante ist doch wesentlich langsamer wie ich finde.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
      CurrentAddItem.CommandText := 'SELECT * FROM ResultURLTable WHERE URL = "' + tempurlstring + '";';
      CurrentAddItem.Open;
      if not CurrentAddItem.IsEmpty then
      begin
       // item found
       CurrentAddItem.First;
       TempParentSitesString := TField(CurrentAddItem.FieldByName('PARENTSITESLIST')).AsString + CurrentURL + sLinkSeperator;
       TempCurrentReferingLinks := TField(CurrentAddItem.FieldByName('REFERINGLINKS')).AsInteger + 1;
       CurrentAddItem.Close;
       CurrentAddItem.CommandText := '';
       // item not found
       SQLQuery.Params.Clear;
       SQLQuery.Sql.Text := 'UPDATE ResultURLTable SET REFERINGLINKS = :REFERINGLINKS, PARENTSITESLIST = :PARENTSITESLIST WHERE URL = :URL;';
       SQLQuery.ParamByName('URL').AsString := tempurlstring;
       SQLQuery.ParamByName('REFERINGLINKS').AsInteger := TempCurrentReferingLinks;
       SQLQuery.ParamByName('PARENTSITESLIST').AsString := TempParentSitesString;
       SQLQuery.ExecSql;
       // add link to linklist
       TempLinkList.Add(tempurlstring + sLinkSeperator);}
      end


jaenicke - Sa 12.07.14 22:32

Du hast doch die Professional Edition. Ist da nicht bei FireDAC der lokale Zugriff auf DBs auf dem gleichen PC dabei? Da sollte dann auch SQLite gehen. Und FireDAC ist deutlich besser als die meisten anderen Zugriffsbibliotheken.


NOS1971 - Sa 12.07.14 22:41

Ok ... werde ich mich alsbald ranmachen und entsprechend meldung machen :-)

Danke sehr und einen schönen abend


NOS1971 - Mo 14.07.14 13:26

Also die Umstellung auf FireDAC habe ich fast geschafft ... da ich aber nun kein TSQLDataBase Objekt mehr habe welches ich für das Syncen des Multithreadings nutze läuft mir das ganze bei mehr als einen thread vor die pumpe ... wenn ich das richtig gelesen habe sollte doch die connection die ich nutze das automatisch handeln ... oder muss ich nun die Connection in der art hier wrappen ?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
  // now add the item
  TMonitor.Enter(MultiThreadedWebAnalyser.AnalyserResultDataBase);
  try
  .
  Codeblock mit DB Zugriff
  .
  finally
    TMonitor.Exit(MultiThreadedWebAnalyser.AnalyserResultDataBase);
  end;


jaenicke - Mo 14.07.14 13:38

Siehe Doku, da ist das genau beschrieben:
http://docwiki.embarcadero.com/RADStudio/XE5/de/Multithreading_(FireDAC)


NOS1971 - Mo 14.07.14 13:52

Das wär ja dann Connection Pooling ... aber SQLite kann doch nur eine Connection ... oder verstehe ich das grad falsch ?


jaenicke - Mo 14.07.14 15:34

Das weiß ich nicht was SQLite in der Hinsicht kann, das habe ich nie mit mehreren Threads genutzt, aber dann bleibt ja noch die erste Möglichkeit. ;-)
(FDManager auf Active setzen und die Nutzung der Verbindung serialisieren, z.B. wie du geschrieben hast mit TMonitor.)


NOS1971 - Mo 14.07.14 22:59

Hmmmm,

also ich finde nichts über nur eine connection ... also versuche ich mal mein glück :-) und mache meldung wenn fertig


jaenicke - Di 15.07.14 06:25

user profile iconNOS1971 hat folgendes geschrieben Zum zitierten Posting springen:
also ich finde nichts über nur eine connection ...
:gruebel:
Der komplette erste Teil ist nur darüber.
Zitat:
FireDAC ist Thread-sicher, wenn die folgenden Bedingungen erfüllt sind:
Ein Verbindungsobjekt und alle zugeordneten Objekte (wie TFDQuery, TFDTransaction usw.) werden zu einem bestimmten Zeitpunkt nur von einem einzelnen Thread verwendet.
FDManager wurde vor dem Start der Threads durch Setzen von FDManager.Active auf True gestartet.
Das bedeutet, dass nachdem ein Thread eine Abfrage geöffnet hat und bis deren Verarbeitung abgeschlossen ist, die Anwendung diese Abfrage und die Verbindungsobjekte nicht in einem anderen Thread verwenden kann. Genauso kann die Anwendung, nachdem ein Thread eine Transaktion gestartet hat und bis die Transaktion abgeschlossen ist, diese Transaktion und die Verbindungsobjekte nicht in einem anderen Thread verwenden.
Dies bedeutet praktisch, dass eine Anwendung den Zugriff auf eine Verbindung für alle Threads serialisieren muss[...]


NOS1971 - Di 15.07.14 11:50

Moin Moin ....

ich bezog das eher darauf ob man mit SQLite nur eine Connection nutzen kann :-)


jaenicke - Di 15.07.14 14:03

Ach so, aber auch das findest du in der Doku wie mir Google grad als erstes Ergebnis ausspuckt:
Suche bei Google FIREDAC SQLITE THREADS
http://docwiki.embarcadero.com/RADStudio/XE6/de/Verwenden_von_SQLite_mit_FireDAC#Transaktionen.2C_Sperren.2C_Threads_und_Cursors_in_SQLite


NOS1971 - Mi 16.07.14 10:13

Ich habe das alles so eingebaut aber ich bekomme es nicht hin sodass es nicht einen fehler nach dem anderen gibt sobald ich mehr als einen thread nutze .... snieff

FDManager erzeuge ich wie folgt:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
 // set database path + filename
 DataBaseFileName := CombinePaths(CurrentTempFolder,'ResultDataBase.db');
 // create threadmanager
 ThreadManager := TFDManager.Create(nil);
 // add connection definition
 ConDefStringList := TStringList.Create;
 ConDefStringList.Add('Database=' + DataBaseFileName);
 ConDefStringList.Add('SharedCache=false');
 ConDefStringList.Add('LockingMode=normal');
 ConDefStringList.Add('Synchronous=normal');
 ConDefStringList.Add('LockingMode=normal');
 ConDefStringList.Add('CacheSize=60000');
 ConDefStringList.Add('BusyTimeOut=30000');
 ConDefStringList.Add('Pooled=true');
 // add connection definition to threadmanager
 ThreadManager.AddConnectionDef('SQLite-Connection','SQLite',ConDefStringList);
 ConDefStringList.Free;


Erzeugung der Connection und der Queries in jedem Thread:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
 // create connection
 ResultDataBaseConnecton := TFDConnection.Create(nil);
 ResultDataBaseConnecton.LoginPrompt := false;
 ResultDataBaseConnecton.TxOptions.Isolation := xiSerializible;
 ResultDataBaseConnecton.UpdateOptions.LockWait := true;
 ResultDataBaseConnecton.ConnectionDefName := 'SQLite-Connection';
 try
  ResultDataBaseConnecton.Connected := true;
  // create queries
  CurrentAnalyseItem := TFDQuery.Create(nil);
  CurrentAnalyseItem.Connection := ResultDataBaseConnecton;
  CurrentAddItem := TFDQuery.Create(nil);
  CurrentAddItem.Connection := ResultDataBaseConnecton;


jaenicke - Mi 16.07.14 15:25

Ich habe noch nirgends gesehen, dass man den TFDManager selbst erzeugen muss, auch in der Doku steht das nicht. Wie kommst du darauf? Wir haben den einfach laut Doku auf Active gesetzt. :gruebel:
Wenn du an der globalen Instanz vorbei selbst einen erzeugst, glaube ich nicht, dass das etwas bewirkt. ;-)


NOS1971 - Mi 16.07.14 15:54

Ja ... das war wohl zunächst der Hauptfehler ... tausend dank ... mir war nicht wirklich klar das ich den TFDManager nicht auch erzeugen muss ... es rennt nun zumindest nicht mehr wie wild vor die pumpe sondern die threads laufen soweit ..... nun differieren scheinbar die anzahl der items in der db mit denen die analysiert werden ... ich tippe mal der status ob das item analysiert ist oder nicht wird nicht richtig geupdated ... da werde ich nun mal nach schauen ... :-)