
Hallo Freunde. Es ist kein Geheimnis, dass Active Record bei der Arbeit an großen Projekten mit komplexer Logik kein Assistent, sondern eine Belastung wird. Stellen Sie sich vor, Sie müssen eine sehr komplexe Abfrage für PostgreSQL auf native Weise (in reinem SQL) durchführen, wobei eine bestimmte Anzahl von Variablen vorhanden sein sollte. Es gibt jedoch eine unangenehme Kleinigkeit in Rails: Die Funktionalität zum Ausführen nativer Abfragen erlaubt nicht die Verwendung benannter Ordner. Aber es gibt eine Lösung :) Getestet und erfolgreich in einem Projekt mit Rails API 5.2 + Ruby 2.6.0 + Postgres 11 implementiert.
Also ein bisschen mehr über das Problem. Die Hauptmethode, mit der Sie Ihre eigenen SQL-Abfragen ausführen können, ist exec_query:
sql = 'SELECT id, name, desc FROM schema.news WHERE id=$1' bindings = [[nil, 100]] new = ActiveRecord::Base.connection.exec_query(sql, 'SQL', bindings).first
Das obige Beispiel zeigt, dass die Bildung von Bindemitteln, gelinde gesagt, an einer Stelle auftritt, wenn wir versuchen, Nachrichten unter der Nummer 100 aus der Datenbank zu erhalten. Bindungen können nicht benannt, sondern nur nummeriert werden. Dies erschwert das Lesen und die Unterstützung nativer Abfragen erheblich. Alternativ können Sie den Methodenaufruf find_by_sql für die Modellklasse verwenden:
sql = 'SELECT id, name, desc FROM schema.news WHERE id=:id' new = New.find_by_sql([sql, id: 100]).first
Hier ist alles angenehmer und verständlicher. Die Frage ist jedoch, dass dies mehr oder weniger akzeptabel ist, wenn Sie eine einfache Anfrage ausführen möchten. Wenn die Anforderung jedoch wirklich kompliziert ist, bedeutet das Ausführen des Modells und von Active Record selbst einen großen Verlust an Geschwindigkeit (langsam) und Leistung (sie verbraucht Serverressourcen). Warum es bei der Arbeit mit nativen Abfragen keine benannten Ordner gibt, ist mir ein Rätsel, aber es gibt eine Lösung: Schreiben Sie meinen eigenen kleinen Wrapper, der sehr einfach mit benannten Ordnern arbeiten kann, was ich auch getan habe.
Ich bringe den Code der statischen Klasse:
Wie Sie dem Code entnehmen können, ist alles so einfach wie eine Ecke des Hauses. Die Abfrage funktioniert folgendermaßen:
sql = 'SELECT id, name, desc FROM schema.news WHERE id=:id' binding = { id: 100 } new = SqlQuery.execute(sql, binding).first
Die Ausgabe ist immer nur ein Hash. Eine kleine Erklärung. Die Methode execute verwendet eine Abfragezeichenfolge und einen Hash mit Bindemitteln. Es ist klar, dass die Bindungen in der Anforderung und im Hash übereinstimmen müssen. Danach durchlaufen wir den Hash mit Bindemitteln und ersetzen sie in der Anforderung selbst durch nummerierte Variablen der Form $ 1, $ 2 usw., wobei gleichzeitig ein Array mit nummerierten Werten erstellt wird, wobei das erste Element des Arrays $ 1, das zweite $ 2 usw. ist. Anschließend führen wir die Abfrage mit der Standardmethode exec_query aus, durchlaufen die Antwort mit dem Mapper und konvertieren die Schlüssel im Hash in Zeichen. Danach führen wir den Mapper erneut gemäß der Antwort aus, wobei wir jeden Feldwert auf den Inhalt von JSON darin überprüfen. Wenn es JSON gibt und es gültig ist, konvertieren Sie es in einen Hash mit Schlüsseln und Symbolen. Wenn das Feld nicht JSON ist, lösen Sie eine Ausnahme aus, in der wir den Wert zurückgeben. Das ist alles.
Wie Sie sehen können, macht es keinen Sinn, Hunderte aller Arten von Edelsteinen zu platzieren und die Gesamtleistung zu verschwenden, um das gewünschte Ergebnis zu erzielen. Sie können viele notwendige Entscheidungen sehr schnell selbst schreiben, nachdem Sie ein Minimum an Zeit und Code aufgewendet haben.
Links zu Github und Cut Gems mit dem Plugin:
github.com/kirill-dan/active_sql_bindingsrubygems.org/gems/active_sql_bindingsViel Glück an alle, bis bald.
Nachdruck aus Ihrem eigenen Blog. Original
hier