[SOLVED] QSqlQueryModel macht Probleme bei Copy & Paste im Code mit MySQL



  • Hallo Forum,

    leider stehe ich vor einem Problem mit dem QSqlQueryModel. Folgendes, ich habe ein Code geschrieben der eine Abfrage einer Datenbank macht und diese Rückantwort dann in einem TableView lädt.

    @QSqlQueryModel *model = new QSqlQueryModel();
    QSqlQuery *qry = new QSqlQuery(db);
    qry->prepare("SELECT * FROM tabelle WHERE id = '"+idVa+"'");
    ui->tableView->setModel(model);@

    Vor dem ui fehlt noch eine Zeile in der das qry ans model übergeben wird, weis aber gerade den Code nicht auswendig. Funktionieren tut es bei mir schon.
    Nun habe ich nochmal ein TableView das ich von der Art her genauso brauche wie der Code oberhalb. Ich habe den Code Makiert und Kopiert und Ihn ein paar Zeilen weiter wieder eingefügt und die Variablen dementsprechend angepasst. Beim Build kommt aber jetzt ein Fehler und sagt das das Model Private ist. Weis den Fehlercode im Debug leider nicht auswendig folgt aber heute Abend alles.
    Klammere ich aber diesen Kopierten Code aus funktioniert das Programm wieder bis auf den Auskommentierten Teil.
    Hatte einer das gleiche Problem schon?

    Gruß

    Alex



  • So sieht der Code aus der einen Fehler ausgibt:

    @QString userEmp = Settings::getUserEmp();
    Database data;
    if(!data.db1Open())
    QMessageBox::critical(this,"Error","Fehler beim öffnen der Datenbank");
    else
    {
    QSqlQuery *qry = new QSqlQuery(data.db1);
    QSqlQueryModel *model = new QSqlQueryModel();
    qry->prepare("SELECT * FROM messageControl WHERE Empfänger = '"+userEmp+"'");
    if(qry->exec())
    {
    model->setQuery(*qry);
    ui->receivedTableWidget->setModel(model);

            data.db1Close();
    
        }
        else
            QMessageBox::critical(this,"Error",qry->lastError().text());
    }@
    

    Das @ui->receivedTableWidget->setModel(model);@ mag er nicht. Der Fehler ist "within this context" und meint das Model. Das den Fehler "virtual void QTableWidget::setModel(QAbstractItemModel*) is private" hat. Kann mir jemand dabei helfen?



  • Hallo Alex,

    spontan fällt mir da nichts auf.
    Was passiert, wenn du die Zeile so:
    @
    ui->receivedTableWidget->setModel(*model);
    @
    änderst?
    Erscheint die gleiche Meldung?
    Und könntest du die komplette Meldung dann posten?

    Gruß
    Erich



  • Hi Erich,

    Ich hab den Zeiger auch schon versucht. Funktioniert auch nicht. Anstatt ein TableWidget nehme ich jetzt ein TableView.
    Damit funktioniert es aber nun hab ich das Problem das wenn ich das View1 mit Daten von der Datenbank anzeigen lasse und dann das zweite View2 auch noch lade leert er mir komplett das erste View1 und zeigt nur leere Zeilen an. Anders herum genauso. Versteh nicht warum er es leert. Weil ein neues query erfolgt oder woran könnte das nun liegen?

    Gruss



  • Hab auch schon versucht ein zweites Query zu benutzen aber funktioniert auch nicht.



  • Hi Alex,
    tableView ist eine gute Wahl - so verwende ich auch meine Datenbank-Tabellen und es funktioniert mit mehreren Tabellen und unterschiedlichen Abfragen in einem Fenster, wenn ich auch unterschiedliche Models verwende. Also tableView1 mit model1, tableView2 mit model2 etc.
    Ich hoffe, das hilft dir weiter.



  • Auch versucht:

    @QString userEmp = Settings::getUserSen();
    Database data;
    if(!data.db1Open())
    QMessageBox::critical(this,"Error","Fehler beim öffnen der Datenbank");
    else
    {
    QSqlQuery *qry = new QSqlQuery(data.db1);
    QSqlQueryModel *model = new QSqlQueryModel();
    qry->prepare("SELECT * FROM messageControl WHERE Empfänger = '"+userEmp+"' ORDER BY Datum");
    if(qry->exec())
    {
    model->setQuery(*qry);
    ui->receivedTableView->setModel(model);
    ui->receivedTableView->hideColumn(0);
    ui->receivedTableView->hideColumn(3);
    ui->receivedTableView->hideColumn(4);
    ui->receivedTableView->hideColumn(5);

            data.db1Close();
    
        }
        else
            QMessageBox::critical(this,"Error",qry->lastError().text());
    }
    
    QString userSen = Settings::getUserSen();
    Database data2;
    if(!data2.db1Open())
        QMessageBox::critical(this,"Error","Fehler beim öffnen der Datenbank");
    else
    {
        QSqlQuery *qry2 = new QSqlQuery(data2.db1);
        QSqlQueryModel *model2 = new QSqlQueryModel();
        qry2->prepare("SELECT * FROM messageControl WHERE Gesendet = '"+userSen+"' ORDER BY Datum ");
        if(qry2->exec())
        {
            model2->setQuery(*qry2);
            ui->sendTableView->setModel(model2);
            ui->sendTableView->hideColumn(0);
            ui->sendTableView->hideColumn(4);
            ui->sendTableView->hideColumn(6);
    
            data2.db1Close();
    
        }
        else
            QMessageBox::critical(this,"Error",qry2->lastError().text());
    }@
    

    Das erste View wird mit einer leeren Zeile geladen (Werte sind Vorhanden) und das zweite View wird mit Inhalt geladen.
    Wenn ich jedes einzeln Lade kommt es mit Inhalt aber sobald ich das andere Lade wird das andere vom Inhalt her geleert aber es bleiben leere Zeilen stehen.



  • Hallo Alex,
    das ist im Prinzip identisch mit meinen Programmen und ich habe einige unabhängige Tabellen mit eigenen Abfragen im Einsatz, die problemlos funktionieren.
    Also muss an einer anderen Stelle die Verbindung zwischen ui->receivedTableView und ui->sendTableView hergestellt werden - vermute ich.
    Ich habe leider keine konkrete Idee, würde aber wie folgt ansetzen:

    • Die beiden tableViews im ui löschen und neu erstellen.
    • Alle Definitionen von model und model2 untersuchen


  • Hi,

    hab mal ein wenig getestet und mal ein View genommen und das neu erstellt.
    Das Verblüffende ist das wenn ich einen Datensatz auswähle mir die ID von der DB hole und in einem neuen Dialog anzeigen lasse kommt das gleiche wieder. Es leert auch die Tabelle als ob er die Verbindung zur Datenbank verliert.

    @QString userEmp = Settings::getUserSen();
    Database data;

    if(!data.db1Open())
        QMessageBox::critical(this,"Error","Fehler beim öffnen der Datenbank");
    else
    {
        QSqlQuery *qry = new QSqlQuery(data.db1);
        QSqlQueryModel *model = new QSqlQueryModel();
        qry->prepare("SELECT * FROM messageControl WHERE Empfänger = '"+userEmp+"' ORDER BY Datum DESC");
        if(qry->exec())
        {
            model->setQuery(*qry);
            ui->messageTableView->setModel(model);
            ui->messageTableView->hideColumn(0);
            ui->messageTableView->hideColumn(3);
            ui->messageTableView->hideColumn(4);
            ui->messageTableView->hideColumn(5);
            data.db1Close();
        }
        else
            QMessageBox::critical(this,"Error",qry->lastError().text());
    }@
    

    Das ist mein Code der eindeutig Funktioniert. Ändere ich diesen um bekomme ich von der QMessageBox einen Fehler:

    @ QString userEmp = Settings::getUserSen();
    Database data;
    QSqlQuery *qry = new QSqlQuery(data.db1);
    QSqlQueryModel *model = new QSqlQueryModel();
    if(!data.db1Open())
    QMessageBox::critical(this,"Error","Fehler beim öffnen der Datenbank");
    else
    {

        qry->prepare("SELECT * FROM messageControl WHERE Empfänger = '"+userEmp+"' ORDER BY Datum DESC");
        if(qry->exec())
        {
            model->setQuery(*qry);
            ui->messageTableView->setModel(model);
            ui->messageTableView->hideColumn(0);
            ui->messageTableView->hideColumn(3);
            ui->messageTableView->hideColumn(4);
            ui->messageTableView->hideColumn(5);
            data.db1Close();
        }
        else
            QMessageBox::critical(this,"Error",qry->lastError().text());
    }@
    

    Ich erstelle einfach Vorher das Query und Model. Aber das mag er überhaupt nicht.
    Der Fehler ist:
    @QSqlQuery::prepare: no driver@



  • Debug bringt beim start folgende Meldung:

    @QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
    QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
    QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
    QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.@



  • Qt beschwert sich hier, dass die Datenbank noch geöffnet ist, die muss vor der erneuten Verwendung geschlossen werden:
    @
    data = QSqlDatabase();
    QSqlDatabase::removeDatabase(db.connectionName());
    @
    Aber du schreibst, dass die Meldung beim Start erscheint?
    An welcher Stelle?
    Wenn ich richtig verstehe, möchtest du in EINER Datenbank zwei Abfragen öffnen...



  • Am Anfang nach dem Benutzer:

    @QSqlQuery *qry = new QSqlQuery(data.db2);
    qry->prepare("SELECT * FROM userList WHERE user = '"+user+"' ");
    if(qry->exec())
    {
    while(qry->next())
    {
    count++;
    ipResponse = qry->value(2).toString();
    userResponse = qry->value(1).toString();
    }

            if(count == 0 && user != "" && user!= "Admin")
            {
                QMessageBox::information(this,"Nicht gefunden","User wurde nicht in der Datenbank gefunden.\nFragen Sie bei ihrem Admin nach.");
    
            }
    
            if(count == 1 && ipAddress == ipResponse && user == userResponse && user != "Admin")
            {
                data.db2.close();
                LanControl con;
                this->close();
                con.setModal(true);
                con.exec();
            }@
    

    Diese wird dann geschlossen. Also kann sie ja nicht offen sein?



  • Nach meiner Erfahrung funktioniert das mit db.close() nicht.
    Versuche doch mal, data.db2.close() durch das zu ersetzen:
    @
    data.db2 = QSqlDatabase();
    QSqlDatabase::removeDatabase(data.db2.connectionName());
    @
    Und noch eine Frage: Musst du die Datenbank an der Stelle schließen?



  • diese Datenbank brauch ich nur einmalig um den User mit der IP zu vergleichen die in der Datenbank hinterlegt ist um das Login zu gewähren. Ansonsten nicht mehr. Soll ich sie dann offen lassen falls ich mit der Datenbank mehr mache?



  • Wenn die Datenbank nicht mehr benötigt wird, solltest du sie schließen, aber versuche das mit den beiden Befehlen.
    (Die Funktion sollte aber auch trotz der Fehlermeldungen gewährleistet sein - so war's zumindest in meinen Programmen.)



  • Verwende für dieses Programm 3 Datenbanken. 1 User DB 1 Message DB und eine Software DB.
    Wenn ich in alle drei immer was brauche soll ich sie dann offen lassen oder Schließen?
    Programm holt sich von der User DB einen Namen um diesen mit einer Nachricht in die Message DB zu schreiben.
    Wieso klappt der befehl:

    @data.db2.close()@

    nicht so gut?



  • Die Information zum Schließen habe ich vor längerer Zeit hier im Forum "z.B. hier: "https://qt-project.org/forums/viewthread/16417gefunden, nachdem ich exakt das gleiche Problem hatte.

    Generell zum Schließen:
    Ich würde die Datenbanken geöffnet lassen, das sollte keine Leistungsprobleme verursachen.



  • Wollte gerade deinen Link anschauen und bekomme folgende Meldung:

    Notice
    The following errors were encountered
    There is no content to display on this link or it has restricted access.



  • Das Kopieren hat nicht geklappt...
    "Korrektur: ":https://qt-project.org/forums/viewthread/16417



  • Ah okay. Klingt sehr interessant was er da gepostet hat. Also die Datenbank so sauber schließen wie du es vorher gezeigt hast.
    Am besten baue ich mein Programm auf eine DB um aber mit mehr Tabellen. Dann kann ich die Verbindung offen lassen in dem Fall.

    In dem ich folgende Funktion ausführe öffne ich ja eine Verbindung zur DB:

    @bool db1Open();@

    Funktion selber:

    @bool Database::db1Open()
    {
    QSettings settings("SETTINGS");
    settings.beginGroup("Einstellungen");
    QString server = settings.value("Server").toString();
    int port = settings.value("Port").toInt();
    settings.endGroup();

    db1 = QSqlDatabase::addDatabase("QMYSQL");
    db1.setDatabaseName("DB");
    db1.setHostName(server);
    db1.setPort(port);
    db1.setUserName("NAME");
    db1.setPassword("PASSWORD");
    
    if(!db1.open())
        return false;
    else
        return true;
    

    }@

    Und wenn ich Sie nicht mehr brauche dann schließen mit folgendem Code:

    @QSqlDatabase::removeDatabase(data.db1.connectionName());@



  • Das Öffnen ist völlig korrekt - zum Schließen solltest du das QSQlDatabase Objekt vor dem removeDatabase noch leeren.
    Sieht dann so aus:

    @
    data.db1. = QSqlDatabase();
    QSqlDatabase::removeDatabase(data.db1.connectionName());
    @



  • Ah vergessen :) gleich probieren. Danke ;)



  • So sieht meine Close-Funktion aus:

    @void Database::db1Close()
    {
    db1 = QSqlDatabase();
    QSqlDatabase::removeDatabase(db1.connectionName());
    }@

    Aber das Problem besteht immer noch :(

    @Access is denied.
    QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
    QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
    QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
    QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.@



  • Ich würde jetzt im Debug-Modus diese Stelle Schritt für Schritt untersuchen.
    Die Meldung "Access is denied" bezieht sich wahrscheinlich auf den User?



  • Jetzt hab ich mit etwas anderen einen hässlichen Fehler. Ich muss seit einem Update von Windows alle neue Projekt mit Adminrechten starten sonst geht das Programm nicht auf.



  • Meldung:

    @Failed to start program. Path or permissions wrong?@
    Ist aber alles richtig



  • Ich lege ein ganz neues Projekt an und der Creator macht das alles richtig aber ich habe immer das kleine Wappen von Win7 wenn etwas Adminrechte braucht. Was das für ne scheiße



  • Hi Alex,
    das ist sicher ein Problem mit den Einstellungen von Win7.
    Google doch mal nach "Win7 Update Admin"



  • Hi,

    Danke hat geholfen. Nun geht es wieder. Sau blöder Fehler xD
    Aber nun zurück zum Fehler das er den Inhalt vom TableView verliert ;)



  • Hi,
    du solltest - auch wenn's mühsam ist - im debug prüfen, was nach den Abfragen in welchem Query steht, z.B.:
    @
    qDebug() << qry.value(0).toString();
    @

    Wenn das abgesichert ist, das gleiche mit den models:
    @
    qDebug() << model->data(model->index(0, 0)).toString();
    @



  • Hallo,

    hab jetzt mal ein kleines Testprogramm gemacht um vielleicht den Fehler leichter zu verstehen:

    Datenbank Klasse:

    @class Database
    {

    public:
    QSqlDatabase dbUser;
    QSqlDatabase dbMemory;

    public:
    Database();

    bool dbUserOpen();
    void dbUserClose();
    
    bool dbMemoryOpen();
    void dbMemoryClose();
    

    };@

    @bool Database::dbUserOpen()
    {
    QSettings settings("A.B.Solution","Memory");
    settings.beginGroup("Einstellungen");
    QString server = settings.value("Server").toString();
    int port = settings.value("Port").toInt();
    settings.endGroup();

    dbUser = QSqlDatabase::addDatabase("QMYSQL");
    dbUser.setDatabaseName("DATENBANK1");
    dbUser.setHostName(server);
    dbUser.setPort(port);
    dbUser.setUserName("USER");
    dbUser.setPassword("PASSWORD");
    
    if(!dbUser.open())
        return false;
    else
        return true;
    

    }

    void Database::dbUserClose()
    {
    dbUser = QSqlDatabase();
    QSqlDatabase::removeDatabase(dbUser.connectionName());
    }

    bool Database::dbMemoryOpen()
    {
    QSettings settings("A.B.Solution","Memory");
    settings.beginGroup("Einstellungen");
    QString server = settings.value("Server").toString();
    int port = settings.value("Port").toInt();
    settings.endGroup();

    dbMemory = QSqlDatabase::addDatabase("QMYSQL");
    dbMemory.setDatabaseName("DATENBANK2");
    dbMemory.setHostName(server);
    dbMemory.setPort(port);
    dbMemory.setUserName("USER");
    dbMemory.setPassword("PASSWORD");
    
    if(!dbMemory.open())
        return false;
    else
        return true;
    

    }

    void Database::dbMemoryClose()
    {
    dbMemory = QSqlDatabase();
    QSqlDatabase::removeDatabase(dbMemory.connectionName());
    }@

    Wenn ich mich anmelde:

    @Database data;
    user = ui->userEdit->text();
    password = ui->passwordEdit->text();
    int count = 0;

    if(!data.dbUserOpen())
        QMessageBox::information(this,"Info","Fehler beim öffnen der Datenbank.\nBitte Verbindung oder IP-Adresse überprüfen.");
    else
    {
        QSqlQuery *qry = new QSqlQuery(data.dbUser);
        qry->prepare("SELECT * FROM userList WHERE user = '"+user+"'");
        if(qry->exec&#40;&#41;)
        {
            while(qry->next())
            {
                userDB = qry->value(1).toString();
                passwordDB = qry->value(2).toString();
                data.dbUserClose();
                count++;
            }
        }
        else
        {
            QMessageBox::critical(this,"MySQL Error",qry->lastError().text());
            data.dbUserClose();
            this->close();
        }
    
        if(userDB == user && passwordDB == password && count == 1)
        {
            Menue men;
            this->close();
            men.setModal(true);
            men.exec&#40;&#41;;
    
        }
        else
        {
            QMessageBox::information(this,"Info","Login fehlgeschlagen. Bitte versuchen Sie es nochmal.");
            ui->userEdit->setText("");
            ui->passwordEdit->setText("");
        }
    
    
    }@
    

    Habe ich keinerlei Probleme. Speichere ich was in die andere Datenbank ab:

    @Database data;
    user = ui->userEdit->text();
    password = ui->passwordEdit->text();
    internetSite = ui->internetsiteLine->text();
    tags = ui->tagsLine->text();

    if(!data.dbMemoryOpen())
        QMessageBox::information(this,"Info","Fehler beim öffnen der Datenbank.\nBitte Verbindung oder IP-Adresse überprüfen.");
    else
    {
        QSqlQuery *qry = new QSqlQuery(data.dbMemory);
        qry->prepare("INSERT INTO internet (id,site,user,password,tags) VALUES (NULL,'"+internetSite+"','"+user+"','"+password+"','"+tags+"')");
        if(qry->exec&#40;&#41;)
        {
            data.dbMemoryClose();
            ui->userEdit->setText("");
            ui->passwordEdit->setText("");
            ui->internetsiteLine->setText("");
            ui->tagsLine->setText("");
    
        }
        else
        {
            data.dbMemoryClose();
            QMessageBox::critical(this,"MySQL Error",qry->lastError().text());
        }
    }@
    

    Kommt wieder die Meldung:

    @QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.@

    Wie kann das sein? Hab ich irgendwo nen Code stehen der Funktioniert aber diesen Fehler produziert?

    Gruß



  • Hi Alex,
    ich kann keinen Fehler finden...
    Versuche doch noch, das Query vor dem Schließen der Datenbank zu beenden:

    @
    if(qry->exec())
    {
    qry->finish();
    data.dbMemoryClose();
    ...
    }
    @



  • Auch versucht aber daran liegt es auch nicht.
    Hab auch folgendes beim Close versucht:

    @dbMemory.removeDatabase("QMYSQL");@

    aber das will ich nicht. Hmmmm.... Beim Login habe ich das Problem nicht. Da bekomme ich keinerlei Meldung. Erst wenn ich eine zweite Verbindung zu einer anderen DB mache bekomme ich die Meldung.



  • Okay habe mein Code etwas angepasst und komme langsam an das Ergebnis heran:

    @dbUser = QSqlDatabase::addDatabase("QMYSQL","UserConnection");@
    @dbMemory = QSqlDatabase::addDatabase("QMYSQL","MemoryConnection");@

    Es liegt daran. Sobald ich einmal die Verbindung gemacht habe verwendet er einen Connection und der ist Standard mässig "Default" als Name.
    Speichere ich jetzt zweimal in dbMemory bekomme ich die Meldung wieder. Beim erstmal speichern nach Programmstart kommt nichts da das erstmal die Verbindung erstellt wurde.

    Ich hoffe es ist etwas verständlich



  • Hab auch bei der Close Funktion folgendes ergänzt:

    @dbMemory.connectionName().remove("MemoryConnection");@

    Er behält aber immer noch die Connection offen trotz remove



  • So...Ich glaube ich hab jetzt die passende Lösung gefunden in der Klasse Database:

    @if(QSqlDatabase::contains("MemoryConnection");@

    ich frage erstmal ob die Verbindung mit der DB schon besteht. Wenn ja dann verwenden dies oder öffne die DB mit diesem.

    Ich glaube das ist so ganz gut :-)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.