Rolf B: Wie Properties aus externen Klassen in Trait bekannt machen?

Beitrag lesen

Hallo MB,

bisher habe ich mit deiner eigentlichen Aufgabe noch nicht befasst.

Aber ich habe schon ähnliche SQL Wrapper geschrieben, in PHP und auch in C#. Du musst berücksichtigen, dass Du mit solchen Wrappern fast immer weniger Möglichkeiten hast als mit direkt formuliertem SQL. Der Sinn solcher Wrapper ist es, Datenbankabfragen unabhängig von einer konkreten Datenbank zu formulieren. D.h. du baust, wenn das zielführend sein soll, nicht nur einen Wrapper, sondern eine Wrapper-Familie, mit SQL-Generatoren für verschiedene Datenbanken.

Also eigentlich nichts anderes als ein ORM Tool, was es schon reichlich fertig gibt. Es selbst zu schreiben kann zwei Gründe haben: man möchte lernen, oder die fertigen Tools sind einem zu schwergewichtig.

Ich denke, dass Dedlfix recht hat. Wenn Du einen SQL Generator haben willst, brauchst Du keine Traits. Sondern Klassen, die du zu einem Statement-Tree zusammensetzt. So ein Tree kann so aussehen:

SELECT-Statement
   - ResultExpressionCollection
      - { ResultExpression }
   - SourceTableCollection
      - { SourceTable }
   - FilterCollection
      - ?
   - GroupExpressionCollection
      - { GroupExpression }
   - GroupFilterCollection
      - { GroupFilter }
   - OrderExpressionCollection
      - { OrderExpression }
   - Limit

Das ist überhaupt nicht trivial, eine ResultExpression kann einfach eine Referenz auf eine Spalte sein, aber auch ein Subselect. Eine SourceTable kann eine Tabelle sein, oder ein Subselect, oder ein Join. Die FilterCollection (WHERE) ist ein Alptraum, wenn Du beliebige Bedingungen zulassen willst. Vermutlich brauchst Du beliebig zusammenstöpselbare AND- und OR-Gruppen, in denen Bedingungen stecken. Eine Bedingung ist ein LIKE, ein IN, ein EXIST, oder =. Die Werte für Bedingungen sind einfache Werte (Spalten, Konstanten), mathematische Ausdrücke, oder Subselects. Wie soll sowas dann am Ende benutzt werden?

$sql = new SqlSelect();
$sql.ResultColumns.Add(new ColumnReference("foo", "a"));
$sql.ResultColumns.Add(new ColumnReference("bar", "a"));
$sql.ResultColumns.Add(new ColumnReference("name", "b"));

$j1 = new InnerJoin();
$j1.Tables.Add(new TableReference("table1", "a"));
$j1.Tables.Add(new TableReference("table2", "b"));
$j1.JoinCondition = new Comparison("=",
                                   new ColumnReference("id", "a"),
                                   new ColumnReference("id", "b"));

$sql.Tables.Add(new TableReference($j1, "x"));

$sql.Filters.Add(new Comparison(">", new ColumnReference("foo", a),
                                     new ConstantValue("47"));

$sql.GetStatement();
// SELECT a.foo, a.bar, b.name
// FROM (table1 a JOIN table2 b ON (a.id = b.id)) x
// WHERE a.foo > 47

Vermutlich müssten noch ein paar Klammern mehr generiert werden, um auf Nummer Sicher zu gehen. Durch Convenience-Varianten der Add-Methoden könnte man auch Schreibarbeit verringern, also z.B.
$sql.ResultColumns.AddColumn("foo", "a");.

De facto wäre das aber die Aufgabenstellung: Konstruktion einer Baumstruktur für eine SQL Abfrage, aus der dann das SQL zusammengesetzt wird. Unter Berücksichtigung von Kleinigkeiten wie der Unterschied zwischen LIMIT in MYSQL, das am Ende steht, und TOP in MS-SQL, das gleich hinter SELECT steht.

Wäre das deine Vorstellung? Ich will jetzt (noch) nicht mit dem ganzen Forum diskutieren, ob diese Vorstellung gut oder schlecht ist. Ich möchte Dir, MB, erstmal nur spiegeln, was ich glaube, verstanden zu haben, und deine Rückmeldung dazu.

Rolf

--
sumpsi - posui - clusi