Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Software-Projekte der Mitglieder (https://www.delphipraxis.net/26-software-projekte-der-mitglieder/)
-   -   TSQLiteDatabase: A SQLite3 Database Wrapper (https://www.delphipraxis.net/140402-tsqlitedatabase-sqlite3-database-wrapper.html)

HalloDu 17. Sep 2009 16:42


TSQLiteDatabase: A SQLite3 Database Wrapper
 
Liste der Anhänge anzeigen (Anzahl: 1)
TSQLiteDatabase: A SQLite3 Database Wrapper
Kompatible SQLite3 Version: 3.6.16
TSQLiteDatabase ist ein nahezu vollständiger OOP-Wrapper um die SQLite3.dll. Er wurde erstellt da ich für eine Anwendung in Delphi 2009 ein kleine, freie Datenbank brauchte nd ich mich für SQLite entschieden hatte. Da ich aber für den Zugriff eine kleine, schlanke Klasse brauchte und mir die im Internet gefundenen Lösungen nicht gefallen haben, habe ich kurzerhand selbst einen Wrapper geschrieben. Zur Nutzung wird die SQLite3.dll benötigt

Features
:arrow: Verbinden mit einer SQLite3 kompatiblen Datenbank
:arrow: Ausführen von SQL-Statments
:arrow: Bindings in den Statments
:arrow: Erzeugen von Collations, Aggregaten und Funktionen
:arrow: Fortschrittsereignis bei längeren Prozessen
:arrow: Autorisieren von bestimmten SQL-Aktionen
:arrow: Blob-Zugriff als Stream
:arrow: Weiterarbeiten mit SQLite-internen Werten
:arrow: Limits setzen
:arrow: In Delphi 2009: Unicode
:arrow: NoVCL kompatibel

Beispiele zur Benutzung
Zur Datenbank verbinden und ein "INSERT" ausführen
Delphi-Quellcode:
var DB: TSQLiteDatabase;
begin
  DB := TSQLiteDatabase.Create('test.db');
  DB.Execute('INSERT INTO TEST (TEST) VALUES ("TEST");');
  DB.Free;
end;
Ein "INSERT" mit Binding
Delphi-Quellcode:
var DB: TSQLiteDatabase;
    Command: TSQLiteCommand;
begin
  DB := TSQLiteDatabase.Create('test.db');
  Command := DB.Command('INSERT INTO TEST (TEST) VALUES (?);');
  Command.Binding[1].AsString := 'Test';
  Command.Execute;
  Command.Free;
  DB.Free;
end.
Auflisten der Daten einer Tabelle
Delphi-Quellcode:
var DB: TSQLiteDatabase;
    Query: TSQLiteQuery;
begin
  DB := TSQLiteDatabase.Create('test.db');
  Query := DB.Query('SELECT * FROM TEST');
  while Query.Next do
    begin
      WriteLn(Query[0].AsString);
    end;
  Query.Free;
  DB.Free;
end.
Beispiel mit vielen "INSERT"s
Delphi-Quellcode:
var DB: TSQLiteDatabase;
    Command: TSQLiteCommand;
begin
  DB := TSQLiteDatabase.Create('test.db');
  DB.Execute('BEGIN TRANSACTION'); // Damit nicht so viele Festplattenzugriffe gemacht werden müssen
  Command := DB.Command('INSERT INTO TEST (TEST) VALUES (?);');
  For I := 1 to 200 do
    begin
      Command.Reset;
      Command.Binding[1].AsString := 'Test'+IntToStr(I);
      Command.Execute;
    end;
  Command.Free;
  DB.Execute('END TRANSACTION');
  DB.Free;
end.
Getestet mit...
:arrow: Delphi 2009 größtenteils, da ich es im Moment in einem Projekt einsetze
:arrow: Delphi 7 rudimentär

SVN: svn://delphidev.net/public/SQLiteDatabase

Wäre klasse, wenn sich das wer von euch mal ansehen oder sogar ein bisschen testen könnte

xZise 17. Sep 2009 19:05

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Moin,
also es gibt ja den "Simple SQLite Wrapper for Delphi". Und was mich da stört ist, dass Objekte zurückgegeben werden. Stattdessen (finde ich), sollten Objekte immer übergeben werden:
Delphi-Quellcode:
type
  TA = class;
  TB = class
  public
    procedure Query(A : TA);
  end;

var
  A : TA;
  B : TB;
begin
  A := TA.Create;
  B := TB.Create;
  try
    TB.Query(A);
  finally
    A.Free;
    B.Free;
  end;
end.
Außerdem vermisse ich das man nachträglich eine/die Datenbank lädt. Zum Beispiel, wenn man die Klasse in einer Klasse kapselt und man erst nachträglich die Datenbank laden will, aber die Klasse halt vorher erstellt, dann ist das immer relativ unschön.

Und was ich auch noch implementieren musste ist eine Möglichkeit Werte zu verschlüsseln und zu entschlüsseln. Übrigens (ich habe es mir nicht angeguckt ehrlich gesagt) wie gehst du mit Strings um? Weil der Simple Wrapper der speichert das als "Binary" sozusagen als Input, statt UTF8/UTF16 zu nehmen (also Input in UTF8 umwandeln und dann UTF8 rausholen und in Ansi-/Unicodestring beim auslesen umwandeln.

Und wie verhält es sich mit verschiedenen Datentypen pro Zelle? Weil in der Dokumentation steht so weit ich weiß, dass die Werte pro Zelle selbst innerhalb einer Spalte verschiedenen sein können/dürfen.

Und auch eine ganz wichtige Frage: Und zwar sind bei dir alle Aufrufe mit UTF8/UTF16? Weil die andere Implementation übergibt einen AnsiString statt einen UTF8String :D Das macht natürlich Probleme mit dem Auslesen.

MfG
xZise

HalloDu 17. Sep 2009 19:11

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Naja, wer möchte kann sich seine TSQLiteQuery und TSQLiteCommand auch selbst instanzieren.

Ja, die Sache mit dem AnsiString ist tatsächlich noch zu überarbeiten, hatte aber im Moment nicht absolute Priorität, da ich in Delphi 2009 damit keine Probleme hatte.

Ganz abgesehen davon, das die ganze Geschichte auch keine schlechte Übung war und zu viel Verständnis für SQLite geführt hat.

xZise 17. Sep 2009 19:15

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Zitat:

Zitat von HalloDu
Naja, wer möchte kann sich seine TSQLiteQuery und TSQLiteCommand auch selbst instanzieren.[...]

Und dann? Du sagst doch "Result := <Klasse>.Create(...)" in "TSQLiteDatabase.Command". Und tada ein Speicherleck ;)

Ich sage natürlich nicht das deine Arbeit schlecht war ^^ aber genau diese Dinge habe im Simple SQLite Wrapper vermisst ;) Und ich finde eigentlich gehört sich sowas wie in TSQLiteDatabase.Command nicht, aber das ist natürlich Geschmackssache.

Und ich bin eigentlich daran in gewisser weise interessiert.

MfG
xZise

HalloDu 17. Sep 2009 19:45

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Mal sehen, ob ich am Wochende dazu komme das umzusetzen. Im Übrigen ist Kritik natürlich immer erwünscht. Die macht das Endprodukt ja nur besser.

Elvis 17. Sep 2009 21:58

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Würdest du in den Factories (DB.Create, ...) Interfaces zurückgeben, gäbe es gar kein Problem.
Die werden durch Referenzzählung autom. freigeben. Dadurch sieht der Code nicht so grausam aus mit all den verschachtelten try-finally-Blöcken, die Delphi sonst so braucht. (kotz!)

Deine normalen Klassen (Command etc) würden diese Interfaces implementieren und alles wäre in Butter.

Mithrandir 29. Sep 2009 15:14

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Sowas habe ich gesucht, super! :thumb:

*gleich mal testen*

Nachtrag: Hmm... Wäre eigentlich ganz praktisch, wenn mir die Klasse n Feedback geben würde, ob die DB-Datei schon existiert oder nicht

Mithrandir 2. Okt 2009 08:44

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
:thumb:

Das Dingens gefällt mir mittlerweile richtig gut, die Bedienung ist simpel und einfach, und dank nonVCL-Fähigkeiten auch für solche Programme geeignet. Dennoch ist mir die Geschwindigkeit negativ aufgefallen. Folgendes Konstrukt:

Delphi-Quellcode:
  procedure TDatabase.AddFile(FileSpecs: TFileSpecs);
  var
    FileCmd: TSQLiteCommand;
  begin
    FileCmd := fDB.Command('INSERT INTO FILES (FILE_PATH, FILE_EXT, FILE_TITLE, FILE_ARTIST, FILE_ALBUM, FILE_YEAR, FILE_GENRE, FILE_LENGTH) ' +
                        'VALUES ( ? , ? , ? , ? , ? , ? , ? , ? );');
    FileCmd.Binding[1].AsString := FileSpecs.fFilePath;
    FileCmd.Binding[2].AsString := FileSpecs.fFileExtType;
    FileCmd.Binding[3].AsString := FileSpecs.fTitle;
    FileCmd.Binding[4].AsString := FileSpecs.fArtist;
    FileCmd.Binding[5].AsString := FileSpecs.fAlbum;
    FileCmd.Binding[6].AsString := FileSpecs.fYear;
    FileCmd.Binding[7].AsString := FileSpecs.fGenre;
    FileCmd.Binding[8].AsInteger := FileSpecs.fLength;
    FileCmd.Execute;
    FileCmd.Free;
  end;
~100 Einträge hinzuzufügen dauert fast 10 Sekunden, imho zu langsam. Ich habe schon, wie von Zeos gewohnt, das Erstellen das Objekts "FileCmd" ausgelagert, und nur noch den Teil mit "FileCmd.Binding[n].AsXYZ" sowie den Execute-Teil drin gelassen. Dann rennt er da zwar durch, aber fügt auch nichts zur DB hinzu. Mache ich irgendwas falsch?

HalloDu 6. Okt 2009 20:42

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Ich muss mich der ganzen Kiste mal über nächstes Wochenende annehmen. Im Moment habe ich leider keine Zeit mich mit dem Problem näher zu beschäftigen. Es freut mich aber das es dir gefällt.

PS: Auch die Sache mit den Interfaces werde ich mir dann mal ansehen.

Mithrandir 6. Okt 2009 20:49

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Ok, cool. :thumb:

HalloDu 15. Okt 2009 20:57

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Entschuldigung das ich mich erst heute wieder melde, hatte recht viel zu tun und das dann über die Arbeit etwas verpennt. Also was dein Problem angeht, so solltest du einfach ein simples Reset vor jedem neuverwenden des Statments aufrufen, dann sollte es gehn. Was die Performance angeht, so ist das Problem, dass wenn du 100 Einträge hinzufügst jedesmal ein Festplattenzugriff gemacht werden muss.
Delphi-Quellcode:
DB.Execute('BEGIN TRANSACTION');
//INSERTS, INSERTS, INSERTS
DB.Execute('END TRANSACTION');
beschleunigt das ganze enorm. (oben Beispiel hinzugefügt)

PS: Was die Interfaces angeht, so bin ich da noch nicht ganz durchgestiegen, es ist aber jeder angehalten, der möchte, sich in diesem Bereich an dem Projekt zu beteiliegen.

Mithrandir 16. Okt 2009 18:33

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Also in meinem Fall so:

Delphi-Quellcode:
procedure TDatabase.AddFile(FileSpecs: TFileSpecs);
  var
    FileCmd: TSQLiteCommand;
  begin
    DB.Execute('BEGIN TRANSACTION');
    FileCmd := fDB.Command('INSERT INTO FILES (FILE_PATH, FILE_EXT, FILE_TITLE, FILE_ARTIST, FILE_ALBUM, FILE_YEAR, FILE_GENRE, FILE_LENGTH) ' +
                        'VALUES ( ? , ? , ? , ? , ? , ? , ? , ? );');
    FileCmd.Binding[1].AsString := FileSpecs.fFilePath;
    FileCmd.Binding[2].AsString := FileSpecs.fFileExtType;
    FileCmd.Binding[3].AsString := FileSpecs.fTitle;
    FileCmd.Binding[4].AsString := FileSpecs.fArtist;
    FileCmd.Binding[5].AsString := FileSpecs.fAlbum;
    FileCmd.Binding[6].AsString := FileSpecs.fYear;
    FileCmd.Binding[7].AsString := FileSpecs.fGenre;
    FileCmd.Binding[8].AsInteger := FileSpecs.fLength;
    FileCmd.Execute;
    FileCmd.Free;
    DB.Execute('END TRANSACTION');
  end;
oder?

HalloDu 16. Okt 2009 18:39

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Das hätte keine Auswirkung auf die Performance. Du musst, wenn du weißt, dass das mehrere Inserts werden werden, diesen Prozess, z.B. eine For-Schleife, mit der Transaktion umgeben, siehe Beispiel oben. Das ist sowieso bei vielen Änderungen in der Datenbank zu empfehlen, und auch bei den meisten Datenbanken machbar. Wenn z.B. ein Problem auftritt, kannst du dann den ganzen Prozess mit einem Rollback wieder rückgängig machen, siehe dazu SQLite Doku

Mithrandir 16. Okt 2009 19:01

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Ah, ok. :) Und wie genau war das mit dem Reset gemeint?

xZise 17. Okt 2009 15:45

Re: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Ich nehme mal er meinte das so:
Code:
BEGIN TRANSACTION
  INSERT ...
  Schleife:
    Binds ...
    Exec ...
    Reset ...
COMMIT
Achso und warum muss man ".Execute('BEGIN TRANSACTION')" aufrufen? Also ich fand es total unpraktisch und habe es so implementiert, wie bei "BeginUpdate"/"EndUpdate". Weil wenn ich das richtig noch in Erinnerung habe, dann kann man nur einmal "Begin Transaction" aufrufen.

MfG
xZise

Wormid 4. Mär 2011 19:26

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Hallöchen,

gibt es eigentlich eine aktuellere Version des Wrappers? Hat sich daran noch etwas getan?

Gruß

Wormid

dGeek 21. Jul 2016 15:29

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Ich habe mal ein wenig gebuddelt und das Thema hier gefunden.
Ich stelle mir gerade die Frage, ob ich von INI zu SQLite3 umstellen sollte oder eher nicht.

In einer INI-Datei meines Projektes können zwischen 1 und 100 Sektionen sein (in der Regel maximal 10) mit etwa (je nach Sektion) 20 bis 30 Schlüsseln.
Es wird relativ häufig auf die einzelnen Schlüssel zugegriffen. Eigentlich sogar immer - egal, was man bei meinem Projekt macht, wird irgendetwas ausgelesen.

Da stellt sich mir nun die Frage: weiterhin INI oder SQLite3?

Sir Rufo 21. Jul 2016 15:51

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Bau dir eine abstrakte Klasse, wo du die Werte abfragen kannst.

Dann dazu die konkrete für eine Ini-Datei (beim reinen Lesen bietet sich auf jeden Fall
Delphi-Quellcode:
TMemIniFile
an) und bei Bedarf weitere (die dann z.B. mit einer SQlite DB spricht).

Dann kannst du die auch direkt vergleichen, was dir genehmer ist oder was im konkreten Fall besser passt.

Eine Ableitung von
Delphi-Quellcode:
TCustomIniFile
die dann mit einer SQlite Datenbank spricht ist natürlich auch denkbar.

dGeek 21. Jul 2016 15:57

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
So wie ich das verstanden habe, kann ich also einfach TIniFile durch TMemIniFile austauschen.
Und dort wo gespeichert wird, müsste ich dann
Delphi-Quellcode:
UpdateFile
aufgerufen werden.

Richtig oder liege ich total falsch?

Sir Rufo 21. Jul 2016 16:01

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Richtig.

Trotz allem würde ich eine Basis-Klasse für die Einstellungen erschaffen und dann konkrete die aus einem bestimmten Topf die Daten beschaffen.

dGeek 21. Jul 2016 16:02

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Um ehrlich zu sein verstehe ich nur Bahnhof :-D

Sir Rufo 21. Jul 2016 16:09

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
So etwas z.B.
Delphi-Quellcode:
unit Unit2;

interface

uses
  System.IniFiles;

type
  TEinstellungen = class abstract
  private
    procedure SetFoo( const Value: string );
    function GetFoo: string;
  protected
    function GetValue( const Key: string ): string; virtual; abstract;
    procedure SetValue( const Key, Value: string ); virtual; abstract;
  public
    property Foo: string read GetFoo write SetFoo;
  end;

  TIniEinstellungen = class( TEinstellungen )
  private
    FIniFile: TMemIniFile;
  protected
    function GetValue( const Key: string ): string; override;
    procedure SetValue( const Key: string; const Value: string ); override;
  public
    constructor Create( const IniFileName: string );
    destructor Destroy; override;
  end;

implementation

{ TEinstellungen }

function TEinstellungen.GetFoo: string;
begin
  Result := GetValue( 'foo' );
end;

procedure TEinstellungen.SetFoo( const Value: string );
begin
  SetValue( 'foo', Value );
end;

{ TIniEinstellungen }

constructor TIniEinstellungen.Create( const IniFileName: string );
begin
  inherited Create;
  FIniFile := TMemIniFile.Create( IniFileName );
end;

destructor TIniEinstellungen.Destroy;
begin
  FIniFile.Free;
  inherited;
end;

function TIniEinstellungen.GetValue( const Key: string ): string;
begin
  Result := FIniFile.ReadString( 'Default', Key, '' );
end;

procedure TIniEinstellungen.SetValue( const Key, Value: string );
begin
  FIniFile.WriteString( 'Default', Key, Value );
  FIniFile.UpdateFile;
end;

end.

dGeek 21. Jul 2016 16:19

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Ok nun hab ich es kapiert!

Was in meinem Fall aber absolut schrecklich wäre ist folgendes:
Delphi-Quellcode:
{ TEinstellungen }

function TEinstellungen.GetFoo: string;
begin
  Result := GetValue( 'foo' );
end;

procedure TEinstellungen.SetFoo( const Value: string );
begin
  SetValue( 'foo', Value );
end;
Dafür habe ich zu viele Werte.

Oder ich kapier den Sinn nicht.

Ich glaube ich wechsle einfach zu TMemIniFile und gut ist. Klasse hin oder her, alles zu ver-komplizieren ist nicht mein Ding.

Ghostwalker 10. Nov 2016 19:36

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Gibts hier was aktuelleres/neues ?

Ansonsten würd ich die Klasse evtl. selbst um ein/zwei Features erweitern :)

Aviator 10. Nov 2016 21:04

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Zitat:

Zitat von Ghostwalker (Beitrag 1353304)
Gibts hier was aktuelleres/neues ?

Ansonsten würd ich die Klasse evtl. selbst um ein/zwei Features erweitern :)

Also ich hatte damals als ich auch auf der Suche war nichts gefunden. Ist jetzt etwa 1 Jahr her. Habe mir dann auch diverse andere Funktionen eingebaut die in dem Wrapper nicht drin waren. Bzw. habe ich nur die Funktionsdefinitionen davon verwendet und mir einen eigenen Wrapper geschrieben. Den kann und möchte ich hier aber leider nicht veröffentlichen. :|

Ghostwalker 10. Nov 2016 21:58

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
hm...wenn ich mir die Source der Klassen angugg ist das schon ein ziemlicher Verhau. :-D

Aber im Moment reicht mir eine kleine Erweiterung aus.

Evtl. werd ich mal auf Basis des eigentlich Wrappers mal noch was Übersichtliches Bauen :)

Ghostwalker 11. Nov 2016 06:04

AW: TSQLiteDatabase: A SQLite3 Database Wrapper
 
Für Interresenten:

unter https://github.com/stijnsanders/TSQLite gibt es eine etwas aktuellere DLL-Umsetzung (der dazugehörige Wrapper ist.....sehr einfach :) )


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:17 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz