Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Software-Projekte der Mitglieder (https://www.delphipraxis.net/26-software-projekte-der-mitglieder/)
-   -   EasyLINQ, eine generische Liste die einfache SQL Befehle ausführt (https://www.delphipraxis.net/162825-easylinq-eine-generische-liste-die-einfache-sql-befehle-ausfuehrt.html)

Daniela.S 6. Sep 2011 14:56


EasyLINQ, eine generische Liste die einfache SQL Befehle ausführt
 
Liste der Anhänge anzeigen (Anzahl: 5)
Hallo liebe DP-ler,

oft braucht man Objektlisten, die gefiltert, sortiert oder gruppiert werden müssen. Unter Delphi Prism bzw. .net gibt es LINQ, das man in solchen Fällen sicher zu schätzen weiss. Leider gibt es unter Delphi selbst nichts dergleichen. Darum habe ich einmal etwas in diese Richtung erstellt. Aus Zeitgründen sicher noch nicht perfekt, aber es arbeitet soweit zufriedenstellend...


Welche SQL-Befehle werden unterstützt?
  • SELECT (optional)
  • TOP(n) Limitiert die Liste auf die ersten n Objekte
  • DISTINCT field Gruppiert die Liste
  • CALC(x) Berechnet den Ausdruck x (bsp. Feld1=Feld2*5+(Feld3/2))
  • WHERE (x) Filtern (<,>,=,<=,>=, zusätzlich. Upper, Lower, Like (% Wildcard), kombinierbar mit OR; AND; XOR)
  • ORDER BY Feld1, Feld2,... Sortierreihenfolge (inkl. ASC/DESC)
  • GROUP BY Feld1, Feld2 Gruppiert die Liste (wie distinct)
  • UPDATE SET (Feld1=Wert1, Feld2=Wert2) Schreibt neue Werte in die Felder



Zur Funktionsweise:
Die Liste kann Klassen oder Records verwalten. Records haben derzeit die Limitierung, dass in die Werte nicht geschrieben werden kann. Somit funktionieren CALC und UPDATE nicht. Eine Exception wird ausgelöst, wenn versucht wird einen der Befehle in Verbindung mit Records zu nutzen. Enumeration wird unterstützt, daher auch "for in" möglich. Handhabung also wie TList<T>.

Durch den Befehl "Execute()" wird das Kommando abgesetzt und eine neues Objekt als Lookup-Liste zurückgegeben. Löschen von Objekten ist in einer Lookup-Liste nicht möglich.

Zur Berechnung von Werten habe ich eine Calculator Klasse eingebunden. Mit ihr lassen sich einfache Rechenoperationen durchführen und deren Ergebnisse wieder in Properties von Klassen zurückschreiben. Unterstützt werden die Operatoren - + / * ^ ( ) sin cos tan sqr log cot sec csc

Was gilt es zu beachten?
  • Ausdrücke müssen in Klammer gesetzt werden... zB. where (a=b) and (c=d) oder update set (a=b, c=d)
  • Für Delphi 2010 & XE

Neues Update:
  • UPDATE Befehl um Werte in Properties schreiben zu können
  • Parser ein wenig überarbeitet
  • Unterstützt Unterklassen
  • Der zweite "Where" Ausdruck kann ein Feld sein
  • Umbenannt, damit es nicht heisst ich sei anmaßend :zwinker:
  • Mit Delphi 2010 getestet
  • Records in der Klasse können gelesen werden

Update, Version 1.3, 30.1.2013

Endlich bin ich mit einigen Projekten auf XE3 umgestiegen, daher auch ein Update dieser Klasse.
  • Kompatibel mit XE3
  • Kompatibel mit 64 Bit
  • Funktion "Where" hinzugefügt
  • Funktion "OrderBy" hinzugefügt
  • Funktion "Distinct" hinzugefügt
  • Funktion "Move" hinzugefügt

Update, Version 1.4, 15.8.2014

Element Operators
  • First, gibt das erste Element zurück
  • Last, gibt das letzte Element zurück

Custom Sequence Operators
  • Combine( TEasyLINQ<T> ), kombinieren von zwei Listen (kopiert die Elemente der übergebenen Liste)

Partitioning Operators
  • Take( n ), gibt die ersten n Elemente zurück
  • Skip( n ), überspringt die ersten n Elemente und gibt alle anderen zurück
  • Odd, gibt alle Elemente mit ungleicher Position (1,3,5...) zurück
  • Even, gibt alle Elemente mit gleicher Position (2,4,6...) zurück

Generation Operators
  • Range( form, to ), Auswahl eines Bereiches von Elementen
  • Repeat( index, n ), Wiederholt das Element mit Index n-mal

Aggregate Operators
  • Aggregate( field ), berechnet das Produkt aller Element von "field"
  • Average( field ), berechnet den Durchschnittswert aller Element von "field"
  • Min( field ), gibt den kleinsten Wert aller Element von "field" zurück
  • Max( field ), gibt den größten Wert aller Element von "field" zurück
  • Sum( field ), berechnet die Summe aller Element von "field"
Update, Version 1.41, 4.9.2014
  • Bug fix: In GetCMD wurden beim Like Command 6 Zeichen gelöscht, anstatt nur 5
Im Laufe der Zeit wird sich sicher noch die eine oder andere Funktion ergeben. Mit dem Parser bin ich noch nicht so ganz glücklich, hier lässt sich auf jeden Fall noch einiges optimieren. Derzeit müssen Ausdrücke in Klammern gesetzt werden, das vereinfacht das Parsen.

Beispiel:
Delphi-Quellcode:
  ClassLinq := TLinq<TMyClass>.Create;
  {...}
  TempLinq := ClassLinq.Execute( 'ORDER BY LastName, FirstName' );
  for item in TempLinq do Memo1.Lines.Add( item.ToString );
  TempLinq.Free;
  {...}
  ClassLinq.Free


Einige SQL-Beispiele aus der beiliegenden Demo:
Delphi-Quellcode:
SELECT WHERE (City="Vienna")
SELECT ORDER BY City,Value
SELECT ORDER BY City,Value DESC
SELECT TOP(3) WHERE (UPPER(Lastname) like "%A%") ORDER BY MySubText.Text
SELECT CALC(value=(value*32+4)/2) ORDER BY value
SELECT TOP(3) WHERE (LOWER(Firstname)="kurt") OR (LOWER(Firstname)="edmund")
SELECT GROUP BY City ORDER BY LastName
SELECT WHERE (MySubText.Text="Sub3") OR (FirstName="Kurt")
UPDATE SET (Firstname="Max", Lastname="Mustermann") WHERE (City="Linz") OR (MySubText.Text="Sub4")
UPDATE SET (Value=CALC(23*2-4)) WHERE (City="Vienna")






Ideen und Wünsche für Erweiterungen und Verbesserungen sind gerne willkommen...

liebe Grüße,
Daniela

Stevie 6. Sep 2011 15:00

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Klingt interessant, werde es mir später mal anschauen. Ich arbeite auch seit einiger Zeit an einer Linq ähnlichen Sache für Delphi (unter Zuhilfenahme der http://code.google.com/p/delphi-coll), die sich dann so etwas ähnliches bietet wie ADO Entity framework/Linq-to-SQL.

Daniela.S 6. Sep 2011 15:04

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
jössas, so viel Zeit habe ich gar nicht. Ich hab das in drei Stunden zusammengebastelt. Im Moment habe ich leider wenig Zeit und solche Sortier- und Gruppiergeschichten halten mich immer unnötig auf. Daher diese kleine (wirklich kleine) Klasse :wink:

DeddyH 6. Sep 2011 15:31

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Was ist denn mit DeHL? Ich habe es noch nicht ausprobiert, aber es liest sich zumindest interessant.

Stevie 6. Sep 2011 15:55

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Zitat:

Zitat von DeddyH (Beitrag 1122163)
Was ist denn mit DeHL? Ich habe es noch nicht ausprobiert, aber es liest sich zumindest interessant.

Delphi Coll ist ein Subset von DeHL. DeHL war vielen Leuten (inklusive mir) zu "fett". Somit hat Alex dann die Collection Sachen rausgenommen und als separate Lib veröffentlicht. Außerdem ist, egal, ob DeHL oder Coll, beides nur Linq-To-Objects. Nix mit SQL. An der Stelle setzt ja mein Konzept an.

DeddyH 6. Sep 2011 15:56

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Ahso. Ja denn.

mschaefer 6. Sep 2011 16:23

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Die Komponente ist eine gute Idee. Vielleicht gerade weil sie klein und überschaubar sit.

Grüße in die Runde

stahli 6. Sep 2011 19:15

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Die Idee ist super!
Werde ich mir demnächst mal gern mit anschauen.

PS: Eine native Linq-Lösung hätte ich mir für XE2 erhofft. (Die tatsächlichen Neuerungen interessieren mich persönlich erst mal weniger.)

Daniela.S 6. Sep 2011 19:29

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Das Problem ist oft, dass die Bibliotheken wahnsinnig überladen sind und teilweise eine hohe Einarbeitungszeit benötigen. Auch sind manche Lösungen recht kompliziert. Dann einen Fehler zu suchen dauert wiederum. Deshalb habe ich es bewusst aufs wesentliche reduziert.

Eine Funktion, die einfache Standard-SQL Befehle versteht, die Objekte danach ausrichtet und als Liste wieder zurückgibt. Man muss sich also nicht wieder in etwas einarbeiten. Es soll auch keinesfalls ein Ersatz für eine Datenbank sein.




Hätte mir auch Linq gewünscht. Vielleicht mit XE3 oder XEⁿ :wink:

Stevie 6. Sep 2011 21:05

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Zitat:

Zitat von Daniela.S (Beitrag 1122228)
Hätte mir auch Linq gewünscht. Vielleicht mit XE3 oder XEⁿ :wink:

Würde mich positiv überraschen, wenn sie die notwendigen und grundlegenden Dinge einbauen würden (würde auch ein Rewrite des dcc32 erfordern, der afaik aber geplant ist?)
Und außerdem kranken die Generics aktuell immernoch an fehlerhafter type inference, wie ich heute wieder feststellen musste, die aber grundlegend für Features wie Linq notwendig ist.

Barry schrieb schon an einigen Stellen, welche Probleme sie mit Lambdas aktuell haben, z.B. hier.

Phoenix 6. Sep 2011 21:17

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Zitat:

Zitat von Stevie (Beitrag 1122246)
Barry schrieb schon an einigen Stellen, welche Probleme sie mit Lambdas aktuell haben, z.B. hier.

Naja, "aktuell" ist relativ. Das Post war von 2008 ;)
Aber es stimmt: Für vollständige Type Inference braucht man einen Multipass Compiler, und Delphi ist historisch nunmal ein Single-Pass Compiler (was nicht heisst, dass der Compiler zwangsläufig alles mehrfach durchgehen muss, aber an manchen Stellen ist das eben nötig).

Stevie 6. Sep 2011 21:36

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Zitat:

Zitat von Phoenix (Beitrag 1122249)
Zitat:

Zitat von Stevie (Beitrag 1122246)
Barry schrieb schon an einigen Stellen, welche Probleme sie mit Lambdas aktuell haben, z.B. hier.

Naja, "aktuell" ist relativ. Das Post war von 2008 ;)
Aber es stimmt: Für vollständige Type Inference braucht man einen Multipass Compiler, und Delphi ist historisch nunmal ein Single-Pass Compiler (was nicht heisst, dass der Compiler zwangsläufig alles mehrfach durchgehen muss, aber an manchen Stellen ist das eben nötig).

Ich schrieb nicht, dass der Post aktuell ist, sondern das Problem, und da sich in der Hinsicht nix getan hat, isses immernoch aktuell ;)

Daniela.S 12. Sep 2011 12:31

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Neues Update...

- Parser überarbeitet
- Update Befehl hinzugefügt
- Unterklassen werden unterstützt

Elvis 12. Sep 2011 15:05

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Mein Delphi 2010 stoplert über 2 Sachen:

In Calculator.Calulate benutzt du eine (scheinend globale?) Variable namens FormatSettings.
Die gibt es bei mir nicht.
Ich habe es so gelöst.
Delphi-Quellcode:
  FormatSettings : TFormatSettings;
begin
  fValid := True;
  if Length( s ) <3 then begin
    fValid := False;
    Exit( 0 );
    end;

  SysUtils.GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, FormatSettings);
Der Call füür getlocale ist sicherlich weniger teuer, als sowas statisch für die Laufzeit der App zu cachen. (Da du ja dann keine Änderungen der Settings bemerken würdest)


Dann benutzt du an 2 Stellen einen Safecast ("as") auf TObject, den mag mein Delphi auch nicht.
Ich musst hier einen Hard-Cast machen:
Delphi-Quellcode:
//TLinQ<T>.Remove
TObject(fItems[index]).Free;
//TLinQ<T>.Clear;
    for item in fItems do TObject(item).Free;
Da du in beiden Fällen vorher die RTTI fragst, ob T eine Klasse ist, musst du hier auch nicht befürchten, dass du den Kater auf TEichhörnchen wurschtelst... :-)

Rein vom API-Design her, finde ich es ein wenig zu einvernehmend die Unit LinQ und die Klasse TLinq zu nennen.
Solche doch sehr offensichtlichen Namen sollten dem Delphi-Team vorbehalten bleiben.
Falls Delphi irgendwann sowas kriegt, könnten Unit- oder Type-Name mit dem kollidieren, was Borlemb aus dem Hut zaubert.
Oder es kollidiert mit den sicherlich vorhandenen anderen LinQ-Workarounds für Delphi.
Oh, und "SELECT" als Prefix ist anscheinend gar nicht nötig. Vllt einfach aus den Beispielen rausnehmen.
Wirkt komisch, wenn man keine Property-liste angeben kann.

Ansonsten ist das sicherlich eine nette Bereicherung für so manchen. :-)

Daniela.S 12. Sep 2011 16:20

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Wie schon geschrieben habe ich es noch nicht auf Delphi 2010 probiert. Derzeit verwende ich die Unit in einem XE Projekt. Aber ich stürze mich gleich nachher darauf :wink:

FormatSettings gibt es erst ab Delphi XE. Beinhaltet von da an den DecimalSeparator.

Am Namen wird es nicht liegen, kann ich gerne ändern. Ich bezweifle jedoch dass Linq in absehbarer Zukunft erscheinen wird. Es wurde 2005 schon mal angekündigt. Was hat sich getan? Nix :| Nichtmal auf Roadmaps konnte ich das bisher erblicken. Solange Lambda, Extension Methods und Type Inference per Default nicht in irgendeiner Art implementiert sind, steht auch die grundlegende Technik dahinter nicht zur Verfügung. Bei XE2 muss ich erst schauen was sich in diesem Bereich getan hat.

Großes Problem ist auch, dass es bei Generics in Delphi 2010 sehr viele Fehler gab. XE hat mir hier auch schon einige Interne Fehler geworfen. XE2 ist da schon um einiges besser.

Und die Rtti funktioniert mit Records scheinbar immer noch nicht.

Tante Edit sagt: Achja, Select ist Optional, kann man um der Syntax-Willen schreiben...

Elvis 12. Sep 2011 16:37

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Zitat:

Zitat von Daniela.S (Beitrag 1123711)
Wie schon geschrieben habe ich es noch nicht auf Delphi 2010 probiert. Derzeit verwende ich die Unit in einem XE Projekt. Aber ich stürze mich gleich nachher darauf :wink:

FormatSettings gibt es erst ab Delphi XE. Beinhaltet von da an den DecimalSeparator.

Ist das eine Funktion oder eine globale Variable?
Letzteres wäre schon ganz schön Kac*e und sollte den Borlembern um die Ohren geworfen werden.
Aber wenn ich FormatSettings als lokale Variable nehme und in Calculate mit der Änderung oben besetze fluppt es.

Zitat:

Und die Rtti funktioniert mit Records scheinbar immer noch nicht.
Dein Bleistift läuft bei D2010 nach meinen Änderungen, wenn man Record auswählt.

Uwe Raabe 12. Sep 2011 16:42

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Zitat:

Zitat von Elvis (Beitrag 1123719)
Ist das eine Funktion oder eine globale Variable?
Letzteres wäre schon ganz schön Kac*e und sollte den Borlembern um die Ohren geworfen werden.

Es ist eine globale Variable! Damit es abwärtskompatibel bleibt, ging es wohl auch nicht anders. Faktisch zeigt FormatSettings.DecimalSeparator und DecimalSeparator so auf denselben Speicherbereich. Ändere ich das eine, ändert sich auch das andere (wäre sonst auch tödlich).

Grundsätzlich sollte man aber immer ein eigenes FormatSettings kreieren, dann klappts auch mit dem Multithreading.

Daniela.S 12. Sep 2011 16:43

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Man kann (oder zumindest habe ich es bis jetzt noch nicht geschafft) in Records zu schreiben. GetValue legt immer eine neue Kopie an. Auch mit TValue.MakeWithoutCopy funktioniert es nicht. Bislang habe ich im Internet auch keine Informationen gefunden woran es liegt.

Ja FormatSettings ist Global. Ein Record das auch verschiedene Funktionen zur Verfügung stellt. Soweit ich gesehen habe kein SingleTon und auch nicht Threadsicher.

Ich lade gleich das Update hoch... eine Minute noch...

Daniela.S 12. Sep 2011 16:55

AW: TEasyLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Update ist Online

DeddyH 12. Sep 2011 16:56

AW: TEasyLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Das waren aber 12 Minuten :mrgreen:

Elvis 12. Sep 2011 16:58

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1123721)
Grundsätzlich sollte man aber immer ein eigenes FormatSettings kreieren, dann klappts auch mit dem Multithreading.

Es ging mir eigentlich darum, dass sich die Settings seit dem Start geändert haben könnten.

Uwe Raabe 12. Sep 2011 17:12

AW: TLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
Zitat:

Zitat von Elvis (Beitrag 1123730)
Es ging mir eigentlich darum, dass sich die Settings seit dem Start geändert haben könnten.

Solange man Application.UpdateFormatSettings nicht auf false setzt, wird das automatisch von TApplication geregelt.

Daniela.S 30. Jan 2013 08:01

AW: TEasyLinq<T>, eine generische Liste die einfache SQL Befehle ausführt
 
neues Update hinzugefügt...

Daniela.S 15. Aug 2014 09:15

AW: EasyLINQ, eine generische Liste die einfache SQL Befehle ausführt
 
Neues Update...

Daniela.S 4. Sep 2014 12:58

AW: EasyLINQ, eine generische Liste die einfache SQL Befehle ausführt
 
Liste der Anhänge anzeigen (Anzahl: 1)
Update...

DSP 4. Sep 2014 17:11

AW: EasyLINQ, eine generische Liste die einfache SQL Befehle ausführt
 
Vielen Dank Daniela, sieht ja gut aus :)

Grüsse
DSP


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:48 Uhr.

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