Home > Tipps & Tricks > Laravel > Laravels Eloquent hat einen Fallstrick bei whereRaw()

Laravels Eloquent hat einen Fallstrick bei whereRaw()

Geschrieben von   admin on    Oktober 16, 2014

Laravels ORM-Layer namens "Eloquent" ist wirklich praktisch. Viele Bedingungen, aus denen Eloquent eine WHERE-Klausel generiert, lassen sich als Einzelbedingungen in Kettenform aneinanderreihen. Sind komplexere Bedingungen gewünscht oder nötig, dann gibt es immer noch die Möglichkeit, per whereRaw() direkt einen Teil einer WHERE-Klausel auf SQL-Ebene zu formulieren.

Es gibt allerdings einen Umstand dabei, den ich als Manko empfinde: Die eingegebene Bedingung wird, so wie sie ist, in das generierte SQL eingesetzt. Und das kann dann für Überraschungen sorgen:

Der folgende Code-Abschnitt hat anders funktioniert, als ich gedacht hätte. Wären keine weiteren Bedingungen hinzugekommen, so wäre der Fehler gar nicht aufgefallen. Bei Verkettung mit anderen Eloquent-Kritierien-Funktionen werden aber mehr Daten geliefert, als (von mir) beabsichtigt.

return $query->whereRaw(<<<EOF_WHERE_RAW
(telearbeiter_id = {$telearbeiter->id})
OR (telearbeiter_id IS NULL AND telegruppe_id IN
    (
        SELECT telearbeiter_zu_gruppen.telegruppe_id FROM telearbeiter_zu_gruppen
        WHERE telearbeiter_id = {$telearbeiter->id}
    )
    AND (status = 'zugeordnet')
)
EOF_WHERE_RAW
);

Das Beispiel entstammt der Praxis. Um es einfacher zu machen: Worauf es ankommt ist das or in einer Bedingung wie a or b.

Warum werden hier nun mehr Daten geliefert, als beabsichtigt? Weil dieser Abschnitt rein textuell in die Gesamt-Abfrage eingebaut wird.

Ich hätte angenommen, dass der Ausdruck insgesamt automatisch mit einem Klammernpaar versehen wird, bevor er als Ausdruck bei der Zusammensetzung der SQL-Anweisung übernommen wird. Gehen wir einmal auf die Boolesche Aussagenlogik zurück: a and (b or c) and d ist etwas anderes, als a and b or c and d. Letzteres ist aufgrund der Operatoren-Rangfolge gleichbedeutend mit (a and b) or (c and d).

Man muss also, sofern man whereRaw() verwendet, um gegen Überraschungen gefeit zu sein, den Gesamt-Term mit einem zusätzlichen Klammernpaar versehen!

Hier also:

return $query->whereRaw(<<<EOF_WHERE_RAW
((telearbeiter_id = {$telearbeiter->id})
OR (telearbeiter_id IS NULL AND telegruppe_id IN
    (
        SELECT telearbeiter_zu_gruppen.telegruppe_id FROM telearbeiter_zu_gruppen
        WHERE telearbeiter_id = {$telearbeiter->id}
    )
    AND (status = 'zugeordnet')
))
EOF_WHERE_RAW
);

Das ist etwas unlogisch. Und etwas, was man seitens Laravel eigentlich verbessern sollte.

Vermutlich wird uns das - aus meiner Sicht - unlogische Verhalten von Eloquent aber erhalten bleiben. Denn eine Änderung würde möglicherweise etlichen existierenden Verwendungen von whereRaw() plötzlich eine andere Bedeutung geben. Unschön. Aber wenn man es weiß (und sich daran erinnert...) kann man diese programmiertechnische Klippe umschiffen.

Kommentare

Kommentar schreiben



(Ihre E-Mail-Adresse wird nicht angezeigt.)


Ungültiger Sicherheitscode

Bitte klicken Sie das Bild an, um einen neuen Sicherheitscode zu laden.