Ankündigung

Einklappen
Keine Ankündigung bisher.

[Erledigt] Design von Klassen für Datenbankabfragen

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • [Erledigt] Design von Klassen für Datenbankabfragen

    Ich bin zur Zeit am Umstellen meiner Webseite auf OOP um den Mehrwert die Objekte mit sich bringen zu erhalten. Gerade Datensätze aus der Datenbank erhalten viele sinnvolle Methoden auch wenn es einen Overhead an Code mit sich bringt.

    Die eigentliche Frage bzw das Problem mit dem ich mich zur Zeit beschäftige sind die Datenbankabfragen. Momentan laufen diese noch mit prozeduraler Programmierung, dh die Abfragen lauten z.B. selectNewsOrderdByTime(), welche die Objekte der Datensätze zurückgeben.
    Dabei haben sich in der Vergangenheit und auch gerade beim Umschreiben zur Zeit immer wieder Probleme ergeben, dass ich gleich mehrere Abfragen ändern musste, wenn sich einzelne Punkte in der Datenbank ändern. Dies hatte ich nun gehofft duch OOP zu verhinden, aber dabei stoße ich immer wieder auf kleinere Probleme welche ich durch Tutorials zu ORM und Studieren von ORM Quellcode leider nicht lösen konnte... :/

    Sobald ich die Funktionen nur in die Manager verteile erhalte ich keinen Mehrwert sondern maximal eine etwas bessere Struktur, aber das ist ja nicht wirklich sinnvoll...
    Wenn ich nun versuche möglichst viel OOP zu benutzen, dann werden Abfragen extrem komplex und sehen plötzlich so aus:
    PHP-Code:
    $newsmanager = new NewsManager$datenbank );
    $newsmanager->addSelect'news_id' 'news_title''news_text''news_language' );

    $newswhere = new WhereConditionWhereCondition::AND );
    $newssubwhere = new WhereConditionWhereCondition::OR );
    $newswhere->addGreaterOrEqual'news_time'12345678 );
    $newswhere->addWhereCondition$newssubwhere );
    $newssubwhere->addEqual'news_language''de' );
    $newssubwhere->addEqual'news_language''en' );

    $newsmanager->addWhereCondition$newswhere );
    $newsmanager->addOrderBy'news_time'true );

    $news $newsmanager->query(); 
    Dieser riesen Code um nur eine einfache Abfrage zu erstellen, welche vllt in dem Code nicht schwer zu verstehen ist, aber schwer auf die schnelle zu überblicken um Änderungen vornehmen zu können.
    Sobald es dann zu JOINs oder UNIONs kommt wird der Code extrem komplex bzw ich stoße mit meinem Design an viele Grenzen!

    Daher meine Frage an euch: Wie desingt ihr eure Klassen für Datenbankabfragen gerade mit dem Hintergedanken von komplexere Abfragen? Nutzt ihr überhaupt sinnvoll OOP dafür oder sollte ich lieber bei einfachen Funktionen wie selectNewsOrderdByTime() für die Abfragen bleiben?

    Ich weiß diese Frage ist sehr komplex und es gibt auch ein paar Themen dazu, aber vielfach wurden nur Ansätze anderer diskutiert und nicht über eine möglichst gute Methode gesprochen!

    Ich hoffe ich werde ein paar interessante Anregungen bekommen, DANKE! =)

    Grüße, Sirke


  • #2
    Naja du designst dabei eigentlich mehr ein SQL Objekt, als dass du eine DB designst.
    Ich baue meine SQL immer per Hand zusammen, und feuer die dann in meine DB Klasse ab. Habe mich dabei mit den Namen am PEAR-Paket orientiert, weil die mir am ehesten zugesagt haben.
    Im Code sieht sowas dann in der Art bei mir aus:
    PHP-Code:
    $sql 'SELECT * FROM test WHERE id=2';
    $result $db->getAll($sql); 
    Für SQL's zusammen zu bauen wollte ich mir auch schon mal ne Klasse basteln, aber das ist ein Haufen Arbeit und im Moment für mich kaum zu realisieren!
    Wenn dich interessiert wie sowas aufgebaut sein kann, kannst du mir ja mal das Zend_Db_Select aus dem Zend Framework anschauen. Das finde ich persönlich für ziemlich gelungen!
    Für meinen Geschmack erzeugst du da für ein SQL zu viele Objekte...
    "My software never has bugs, it just develops random features."
    "Real programmers don't comment. If it was hard to write, it should be hard to understand!"

    Kommentar


    • #3
      Schöner geht sowas auch meist mit einem "liquid interface" (?). Prinzip ist es das Objekt in sonst leeren Methoden zurückzugeben. Das erzeugt sehr leserliche Abfragen wie z.B. bei Kohana:

      PHP-Code:
      DB::select()->from('table_name')->having('column','=','value')->and_having('column2','=','value'); 

      Kommentar


      • #4
        Jo so ähnlich wirds auch im Zend Framework gemacht.
        Was ich mit meiner Aussage sagen wollte ist nur, das so ein interface halt ein Haufen Arbeit ist...
        "My software never has bugs, it just develops random features."
        "Real programmers don't comment. If it was hard to write, it should be hard to understand!"

        Kommentar


        • #5
          Hallo Sirke,

          schau dir mal das Interface des GenericORMapper des APF an. Hier wird mit einem GenericCriterionObject und einem Satz an Methoden gearbeitet, die für alle Abfragen kompatibel sind. Vielleicht hilft dir die Methoden-Signatur ein wenig weiter.

          Kaskaden wie die zuletzt gezeigte halte ich für Humbug, da hierdurch keine wirklich hilfreiche Abstraktion geschaffen wird. Wenn Abstraktion, dann bitte ohne eine sehr SQL-ähnliche Logik in der Signatur (z.B. having).
          Viele Grüße,
          Dr.E.

          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          1. Think about software design before you start to write code!
          2. Discuss and review it together with experts!
          3. Choose good tools (-> Adventure PHP Framework (APF))!
          4. Write clean and reusable software only!
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

          Kommentar


          • #6
            Ich habe mir meine Klasse ähnlich Deinem Beispiel aufgebaut:

            PHP-Code:
            $db = new db;
            $db->setTable('Startseite');
            $db->setWhere("aktiv = '?'"'ja');
            $db->setQuery('select'); 
            Den Connector in der Klasse selbst habe ich über pdo geregelt und kann daher auch andere Datenbanken nutzen. Ich finde den Code gut lesbar/nachvollziehbar und eben auch erweiterbar.

            Für eine erweiterte Abfrage (2 oder mehr Tabellen) brauche ich nur die folgende Zeile hinzufügen und bleibe (meine Meinung) flexibel
            PHP-Code:
            $db->addTable('Artikel''artnr'); 
            Gruß Werner
            Mein kleines Projekt: Fussball Satrup
            Wird ein OpenSource CMS für Fussballvereine

            Kommentar


            • #7
              Zitat von woskamp Beitrag anzeigen
              Den Connector in der Klasse selbst habe ich über pdo geregelt und kann daher auch andere Datenbanken nutzen. Ich finde den Code gut lesbar/nachvollziehbar und eben auch erweiterbar.
              Dem Irrglauben bin ich auchmal aufgesessen.

              Das Problem ist z.b. der Befehl Limit. Da nützt dir auch PDO nichts mehr wenn du diese auf Oracle oder MSSQL umstellst, bzw. anders ausgedrückt: die ausgewählte Engine den Teilbefehl nicht unterstützt (selbst wenn er nur anders heißt).

              Ich habe es so gelöst da sich mir einen OR-Mapper gebastelt habe wodurch so riesige Listings entstehen wie hier genannt. Hinter diesem OR-Mapper steht ein Parser welcher aus der Objektstruktur einen SQL-Query bastelt. Das funktioniert auch relativ zügig und gut, ich muss bloß für jede Engine einen eigenen Parser erzeugen.

              Um solche Monsterlistings zu vermeiden habe ich einige kleine Klassen geschrieben die übliche Aufgaben übernehmen wie z.B. das erzeugen einer Liste. Diese Klasse besitzt dann Methoden wie addSort(), addCondition() und setzt deren Parameter dann über den OR-Mapper um. So bleibe ich bei meinen Listen flexibel was Sortierung und Inhalte angeht (z.B.Einschränkung über eine Suche), habe aber nicht jedes mal wenn ich eine Liste rbauche eine wig langes Listung mit Objekten und Methodenwirrwarr.
              "Alles im Universum funktioniert, wenn du nur weißt wie du es anwenden musst".

              Kommentar


              • #8
                Das Problem ist z.b. der Befehl Limit.
                Aber Gegenstücke dazu gibt es auch in anderen DBMS. Und wenn man eine Klasse zum Bauen von Queries hat, dann kann man diese eben an Oracle anpassen..

                Kommentar


                • #9
                  Vielen Dank für die vielen Denkanstöße! Habe mir alles etwas genauer angesehen und den Ansazu von dr.e. sagt mir am ehesten zu, auch wenn der Aufwand für Interfaces und Abstracts evtl sehr groß sein wird.

                  Ich denke am Ende wird es auf ein Mittelding zwischen einem richtigen ORM und festen Vorgaben für Relationen hinauslaufen!

                  Nochmal vielen Dank für die vielen Denkanstöße und damit ist das Thema auch erledigt und ich mache mich mal ans Design!

                  Kommentar


                  • #10
                    Ich habe mir einfach ein Interface geschaffen, das ich dann in Klassen für verschiedene DBMS umsetzen kann. Das Problem der unterschiedlichen SQL-Syntax habe ich bisher noch nicht lösen können, dachte dabei aber an einen Parser der in der jeweiligen Klasse von MySQL Syntax zu der jeweiligen Syntax umstellt.

                    PHP-Code:
                    <?php
                    /***************************************************************************
                     *                           Database-interface interface
                     *                     (c) Copyright 2010 jw-lighting
                     *
                     *             Published under Creative Commons 3: BY-NC-SA
                     *
                     * This class and all its sub-a nd parentclasses and files comes with
                     * absolutly NO WARRANTY. You can use this code, but only by your own risc.
                     *
                     ***************************************************************************/

                    /**
                     * Interface for XY database-interfaces
                     * @author Jan Wiese <jw-lighting@ewetel.net>
                     * @copyright jw-lighting 2010
                     * @license Creative Commons 3: BY-NC-SA
                     * @version 0.2.6.stable
                     * @package XY
                     * @subpackage XY_DBi
                     */
                    interface TicketService_DBi{
                        
                        
                    /* Suggestion for constants and properties:
                         *
                         *  const DB_USER;
                         *  const DB_PASS;
                         *  const DB_HOST;
                         *  const DB_DATABASE;
                         *
                         *  protected $dbCon;
                         *  protected $saveQuickQueryResults;
                         *  protected $lastResult;
                         *
                         *  protected function parseQuery($query, $safeValues=array());
                         *
                         */
                        
                        
                        
                    public function connect();
                        public function 
                    close();
                        
                        public function 
                    quickQuery($query$safeValues=array());
                        public function 
                    query($query$safeValues=array());
                        public function 
                    getResult(&$result=null);
                        public function 
                    getResultNum($result);
                        
                        public function 
                    setQuickQuerySave($value);
                        public function 
                    getQuickQuerySave();
                        
                        
                    /**
                         * @since 2.6.stable
                         */
                        
                    public function getConnection();
                        
                    }

                    Kommentar


                    • #11
                      @jw-lighting: dass die Klasse Konstanten für variable Daten hat ist IMHO ein Design-Fehler. Solche Informationen sollten entweder als Konfiguration ausgelagert oder per DI injiziert werden. Was soll setQuickQuerySave() machen?
                      Viele Grüße,
                      Dr.E.

                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                      1. Think about software design before you start to write code!
                      2. Discuss and review it together with experts!
                      3. Choose good tools (-> Adventure PHP Framework (APF))!
                      4. Write clean and reusable software only!
                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                      Kommentar

                      Lädt...
                      X