Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

SQL je Tabelle eine Klasse



  • Es ist eher eine Laien Frage was OOP Entwicklung betrifft. Ich möchte eine SQLite DB in QT abbilden. Hierzu sollen für jede Table eine Klasse erstellt werden. Ich habe einen DBController, der die Verbindung zur DB erstellt und einen weiteren Controller, der Daten aus der DB anzeigen soll (Select Query). Die Verbindung zur DB steht bereit, allerdings werden die Daten in der TableView nicht angezeigt.
    Zusätzlich sollen die verschiedenen Selects über eine TableView im MainWindow laufen. Wenn es denn Sinn macht.

    Hier mal mein Code:
    DBController.h

    class DbController : public QMainWindow
    {
        Q_OBJECT
    
        public:
            DbController(QWidget *parent = 0);
            ~DbController();
    
            bool checkIfDbConnected();
            bool isConnectionOpen();
            void closeDbConnection();
    
        private:
            Ui::StartWindow *ui;
            QSqlDatabase m_erpDb;
    
            QSqlError getLastError();
            QSqlQueryModel *selectTable(QString);
    };
    

    DBController.cc

    DbController::DbController(QWidget *parent)
        : QMainWindow(parent)
    {
        m_erpDb = QSqlDatabase::addDatabase("QSQLITE");
        m_erpDb.setDatabaseName("F:/Ramsys_ERP/ramsys_erp_test.db");
        m_erpDb.open();
    
        if (!m_erpDb.isOpen())
            qDebug() << "Error: connection with database failed!";
        else
            qDebug() << "Database connected!";
    }
    
    DbController::~DbController()
    {
        if (m_erpDb.isOpen())
            closeDbConnection();
    }
    
    bool DbController::isConnectionOpen()
    {
        return m_erpDb.isOpen();
    }
    
    void DbController::closeDbConnection()
    {
        m_erpDb.close();
        m_erpDb.removeDatabase(QSqlDatabase::defaultConnection);
        qDebug() << "Database connection closed!";
    }
    
    bool DbController::checkIfDbConnected()
    {
        return m_erpDb.isOpen();
    }
    
    QSqlError DbController::getLastError()
    {
        return m_erpDb.lastError();
    }
    

    MainWindow.h

    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
        public:
            MainWindow(QWidget *parent = 0);
            ~MainWindow();
    
        private slots:
            void btn_editOffer();
            void btn_addOffer();
            void on_table_DatabaseList_activated(const QModelIndex &index);
    
        private:
            Ui::MainWindow *ui;
            QSqlDatabase m_erpDb;
            QSqlQueryModel *model;
    };
    

    MainWindow.cc

    MainWindow::MainWindow(QWidget* parent)
        : QMainWindow(parent)
    
    {
        ui->setupUi(this);
    
        TestController offer;
     }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    

    Die anderen Funktionen sind noch nicht implementiert.

    TestController.h

    class TestController : public QMainWindow
    {
        Q_OBJECT
    
        public:
            TestController (QWidget *parent = 0);
            ~TestController ();
    
            void initOfferView();
    
    
        private:
            Ui::MainWindow *ui;
            QSqlDatabase m_erpDb;
    
            void disconnectFromServer();
            QSqlQueryModel *model;
            QSqlError getLastError();
    
    };
    

    TestController.cc

    TestController ::TestController (QWidget* parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        m_erpDb  = QSqlDatabase::database();
        if (m_erpDb.isOpen())
            qDebug() << "Database from offer is open";
        else
            qDebug() << "Database from offer is closed";
    
        initOfferView();
    }
    
    TestController ::~TestController ()
    {
    
    }
    
    void TestController ::initOfferView()
    {
        model = new QSqlQueryModel();
        QSqlQuery query;
    
        query.prepare("select * from angebot");
        query.exec();
    
        ui -> table_DatabaseList -> setModel(model);
        model -> setQuery(query);
        ui -> table_DatabaseList -> show();
        qDebug() << (model -> rowCount());
        qDebug() << model -> lastError().isValid();
    
        ui -> table_DatabaseList -> setEditTriggers(QAbstractItemView::NoEditTriggers);
    
        model -> setHeaderData(0, Qt::Horizontal, QObject::tr("Angebots Nummer"));
        model -> setHeaderData(1, Qt::Horizontal, QObject::tr("Art des Angebotes"));
    
        ui -> table_DatabaseList -> horizontalHeader() -> resizeSections(QHeaderView::ResizeToContents);
    
    }
    

    Was den Aufbau eines OOP Projektes from scratch betrifft, bin ich noch nicht so belesen, wie an der Frage wahrscheinlich erkennbar ist.
    Bin ich auf dem richtigen Weg?


  • Lifetime Qt Champion

    @Paarn said in SQL je Tabelle eine Klasse:

    QSqlDatabase m_erpDb;

    Bitte https://doc.qt.io/qt-5/qsqldatabase.html lesen - du solltest KEINE QSqlDatabase variablen nutzen, da QSqlDatabase bereits die Verbindungen für dich verwaltet (https://doc.qt.io/qt-5/qsqldatabase.html#database).
    Falls open() fehlschlägt solltest du auch https://doc.qt.io/qt-5/qsqldatabase.html#lastError ausgeben.

    Warum hast du

    QSqlDatabase m_erpDb;
    

    auch noch in MainWindow, wo du es doch schon in DbController hast?!
    Was ist das

    OfferController offer;
    

    ? Dir ist schon klar, dass offer eine lokale Variable in MainWindow Konstruktor ist und zerstört wird sobald der Konstruktor verlassen wird?
    Warum hast du QSqlDatabase m_erpDb; in OfferControloler ?!
    Warum hast du Ui::MainWindow *ui; in OfferController? Das ist doch die UI von deinem MainWindow und hat nichts in OfferController zu suchen!
    Dieser Code mach so keinen Sinn und kann auch gar nicht funktionieren.



  • Ich bin in Qt noch neu. Ich weiß auch, dass es sich hier um grundlegende Fragen zur OOP handelt. Auch hier bin ich leider noch etwas unerfahren.
    Deswegen meine Frage, damit ich nicht direkt alles falsch aufbaue.
    Dennoch danke für die prompte Antwort.

    Ich hab im Code auch mal den OfferController ind TestController umbenannt.

    @jsulm said in SQL je Tabelle eine Klasse:

    @Paarn said in SQL je Tabelle eine Klasse:

    QSqlDatabase m_erpDb;

    Bitte https://doc.qt.io/qt-5/qsqldatabase.html lesen - du solltest KEINE QSqlDatabase variablen nutzen, da QSqlDatabase bereits die Verbindungen für dich verwaltet (https://doc.qt.io/qt-5/qsqldatabase.html#database).
    Falls open() fehlschlägt solltest du auch https://doc.qt.io/qt-5/qsqldatabase.html#lastError ausgeben.

    Open Schlägt nicht fehl. Die Verbindung zur DB besteht, auch im Konstruktor zu TestOffer. In der Methode initOfferView wird offensichtlich das Select Query ausgeführt. rowCount() zeigt die richtige Anzahl an, aber lastError() gibt QSqlError("", "", "").
    QSqlDatabase als Variable hab ich aus anderen Beispielen. Ich möchte die offene DB mit den versch. Klassen verlinken und nutzen.

    Warum hast du

    QSqlDatabase m_erpDb;
    

    auch noch in MainWindow, wo du es doch schon in DbController hast?!

    Warum hast du QSqlDatabase m_erpDb; in OfferControloler ?!

    Das ist mein Versuch die DB Verbindung, die der DbController erstellt im MainWindow/TestController nutzen zu können. Ich möchte die offene DB mit den versch. Klassen verlinken und nutzen.

    Was ist das

    OfferController offer;
    

    ? Dir ist schon klar, dass offer eine lokale Variable in MainWindow Konstruktor ist und zerstört wird sobald der Konstruktor verlassen wird?
    Warum hast du Ui::MainWindow *ui; in OfferController? Das ist doch die UI von deinem MainWindow und hat nichts in OfferController zu suchen!
    Dieser Code mach so keinen Sinn und kann auch gar nicht funktionieren.

    Ich möchte die TableView im MainWindow mit dem TestController nutzen, da muss ich die ja bekannt machen.


  • Lifetime Qt Champion

    @Paarn said in SQL je Tabelle eine Klasse:

    Das ist mein Versuch die DB Verbindung, die der DbController erstellt im MainWindow/TestController nutzen zu können. Ich möchte die offene DB mit den versch. Klassen verlinken und nutzen.

    Wozu hast du dann DbController wenn du dann eh direkt QSqlDatabase benutzt? Warum benutzt du nicht DbController stattdessen? Und wie ich vorher schon geschrieben habe: du brauchst all diese m_erpDb variablen gar nicht (und auch nicht DbController), da QSqlDatabase die Verbindungen für dich verwaltet (lese bitte den Link, den ich vorher gepostet habe).

    "Ich möchte die TableView im MainWindow mit dem TestController nutzen, da muss ich die ja bekannt machen." - noch mal: offer wird zerstört sobald der MainWindow Konstruktor verlassen wird und existiert danach gar nicht mehr. Und du solltest niemals interne Implementierungsdetails einer Klasse nach außen sichtbar machen (wie Ui::MainWindow *ui) - es verstößt ziemlich heftig gegen OOP Regeln.


  • Banned

    Maybe you can use English so i might can help you!



  • @jsulm said in SQL je Tabelle eine Klasse:

    @Paarn said in SQL je Tabelle eine Klasse:

    Das ist mein Versuch die DB Verbindung, die der DbController erstellt im MainWindow/TestController nutzen zu können. Ich möchte die offene DB mit den versch. Klassen verlinken und nutzen.

    Wozu hast du dann DbController wenn du dann eh direkt QSqlDatabase benutzt? Warum benutzt du nicht DbController stattdessen? Und wie ich vorher schon geschrieben habe: du brauchst all diese m_erpDb variablen gar nicht (und auch nicht DbController), da QSqlDatabase die Verbindungen für dich verwaltet (lese bitte den Link, den ich vorher gepostet habe).

    Folglich brauch ich QSqlDatabase nicht, nutze dafür den DbController? Dann wird m_erpDb meine DbController Variable.

    "Ich möchte die TableView im MainWindow mit dem TestController nutzen, da muss ich die ja bekannt machen." - noch mal: offer wird zerstört sobald der MainWindow Konstruktor verlassen wird und existiert danach gar nicht mehr. Und du solltest niemals interne Implementierungsdetails einer Klasse nach außen sichtbar machen (wie Ui::MainWindow *ui) - es verstößt ziemlich heftig gegen OOP Regeln.

    Das ist richtig. Danke nochmal.



  • @MalitheBIG

    I want to map an SQLite DB in QT. For this purpose a class should be created for each table. I have a DBController which creates the connection to the DB and another controller which should display data from the DB (Select Query). The connection to the DB is ready, but the data is not displayed in the TableView.
    Additionally the different selects should run over a TableView in the MainWindow. If it makes sense.
    As I now know, either QSqlDatabase is redundant when I use the DbController. Or the other way around.

    Regarding the structure of an OOP project from scratch, I am not yet as well-read as the question probably indicates.


  • Lifetime Qt Champion

    @Paarn Es ist dein Code, ich will aber noch ein mal auf die Dokumentation verweisen:
    "Warning: It is highly recommended that you do not keep a copy of the QSqlDatabase around as a member of a class, as this will prevent the instance from being correctly cleaned up on shutdown. If you need to access an existing QSqlDatabase, it should be accessed with database(). If you chose to have a QSqlDatabase member variable, this needs to be deleted before the QCoreApplication instance is deleted, otherwise it may lead to undefined behavior."
    https://doc.qt.io/qt-5/qsqldatabase.html



  • @jsulm Danke für deine Geduld.
    Ich schaue es mir nochmals genauer an und baue den Controller dann um.


Log in to reply