Error "no matching member function for call to bindValue"
-
Goodmorning to all,
I'm using Qt version 5.14.0 and I'm tring to develop a database with SQL.
The problem is that when I call the method bindValue, I get the error:no matching member function for call to bindValue
candidate function not viable: requires 3 arguments, but 2 were providedThe sample code is the shown below:
#ifndef ALBUMDAO_H #define ALBUMDAO_H class QSqlDatabase; #include "album.h" #include <QList> class AlbumDao { public: AlbumDao(QSqlDatabase& database); void init() const; void addAlbum(Album& album) const; void updateAlbum(const Album& album) const; void removeAlbum(int id) const; QList<Album*> albums() const; private: QSqlDatabase& mDatabase; }; #endif // ALBUMDAO_H
#include "albumdao.h" #include <QSqlDatabase> #include <QSqlQuery> #include <QSql> #include <QVariant> #include "databasemanager.h" AlbumDao::AlbumDao(QSqlDatabase &database) : mDatabase(database) { } void AlbumDao::init() const { if (!mDatabase.tables().contains("albums")) { QSqlQuery query(mDatabase); query.exec("CREATE TABLE albums (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)"); } } void AlbumDao::addAlbum(Album &album) const { QSqlQuery query(mDatabase); query.prepare("INSERT INTO albums (name) VALUES (:name)"); query.bindValue(":name", album.name()); query.exec(); album.setId(query.lastInsertId().toInt()); } void AlbumDao::updateAlbum(const Album &album) const { QSqlQuery query(mDatabase); query.prepare("UPDATE albums SET name = (:name) WHERE id = (:id)"); query.bindValue(":name", album.name()); query.bindValue(":id", album.id()); query.exec(); //DatabaseManager::debugQuery(query); } void AlbumDao::removeAlbum(int id) const { QSqlQuery query(mDatabase); query.prepare("DELETE FROM albums WHERE id = (:id)"); query.bindValue(":id", id); query.exec(); } QList<Album *> AlbumDao::albums() const { QSqlQuery query("SELECT * FROM albums", mDatabase); query.exec(); QList<Album*> list; while(query.next()) { Album* album = new Album(); album->setId(query.value("id").toInt()); album->setName(query.value("name").toString()); list.append(album); } return list; }
Have you got any advices?
Thank you in advanced. -
@davidino said in Error "no matching member function for call to bindValue":
mDatabase(new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE"))),
albumDao(*mDatabase)This is wrong on so many levels.
First: don't store a QSqlDatabase member variable like explained in a warning in the QSqlDatabase documentation.
Second: even less as a pointer
Third: if you have to deference QSqlDatabase, it means you are already having issues in your design.Are you using only the default connection ? If so, then there's no need to pass anything around as it is the connection used when you don't pass any specific parameter to e.g. QSqlQuery.
If you have several different connections, then pass their name around so the classes concerned can all QSqlDatabase::database to get the correct connection to use. -
Hi @davidino,
query.bindValue(":name", album.name());
You mean here? So please provide the function signature of Album::name().
Btw.: Why are you using Qt 5.14? It is not released yet. Have you tried 5.12.x or 5.13.x?
Regards
-
@davidino said in Error "no matching member function for call to bindValue":
no matching member function for call to bindValue
Hi
Could you try to include
#include <QVariant>
in the albumdao.cpp
Not that. ( thx jonb )also as a note:
You dont need to keep the database around to be used with QSqlQuery
as it has a default connection concept.
Which allows to simply open the database in some part of the application and
simply do QSqlQuery query; ( anywhere in the app)
and it will use the default database.
https://doc.qt.io/Qt-5/qsqldatabase.htmlalso Docs says
"
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. "So make sure you are not jumping into that trap :)
-
@mrjj
I was indeed tempted by your answer, but the OP's code already shows#include <QVariant>
in the
albumdao.cpp
. Which leaves @aha_1980'sSo please provide the function signature of
Album::name()
.though it seems likely that will just be a string... ah, if it is perhaps(?) a
std::string
that won't work without some coercion.Make sure whatever your Qt 5.14 is it has not lost the https://doc.qt.io/qt-5/qsqlquery.html#bindValue overload! Also, I assume you are getting a compile-time error (check the line number and tell us which line it is?), but you should anyway test the run-time return value of your
prepare()
(plusexec()
etc.) statements. -
Hello,
Thank you all for your support. I'm surprised that after a few hours, I received these many answers :).
For info, the error is signed as Semantic Error.To @aha_1980, yes it's query.bindValue(":name", album.name()); Thank you. Regarding the Qt version, I've build image and sdk from the last release of meta-boot2qt (open-source version) for a raspberrypi0 board.
To @mrjj, regarding the fact that QSqlQuey doesn't need the reference to database, how do I set the database name and driver that are meant to be used (MYQSL in my case)? An if I have multiple databases?
Regarding the class that I post, thank you for your observation. Actually I have a class "databaseManager", where I create the database object, and take care of its deletion. Then I've created other classes like "albumdao" that I posted, where I add queries, otherwise databaseManager would have been very long. Since the database is passed as reference, it's not up to "albumdao" to delete the database but to "databaseManager". Isn't it as safe as getting it using database()? (in both case, the database deletion is perform by database class). Thank you for your comment, I could be wrong.To @JonB Yes, the method still has the following signature:
void bindValue(int pos, const QVariant& val, QSql::ParamType type = QSql::In);, even though I specify the third argument, it doesn't work,
I could run the project both prepare and exec return true. Thank you,Below album code:
#include "album.h" Album::Album(const QString &name) : mId(-1), mName(name) { } int Album::id() const { return mId; } void Album::setId(int id) { mId = id; } QString Album::name() const { return mName; } void Album::setName(const QString &name) { mName = name; }
#ifndef ALBUM_H #define ALBUM_H #include "gallery-core_global.h" #include <QString> class GALLERYCORE_EXPORT Album { public: explicit Album(const QString& name = ""); int id() const; void setId(int id); QString name() const; void setName(const QString& name); private: int mId; QString mName; }; #endif // ALBUM_H
-
Hi,
QSqlDatabase::addDatabase has a parameter which allows you to have several different connections.
QSqlDatabase::database allows you to retrieve the connection with the given name.
-
Hello @SGaist,
thank you for your answer. Yes, in my databaseManager I use, the following and I pass the newly created database to albumdao as reference:DatabaseManager::DatabaseManager(const QString &path) : mDatabase(new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE"))), albumDao(*mDatabase) {}
Now I understand that using QSqlDatabase::database I can retrieve the database by name without providing the reference as I did, I could simply pass the name.
Do you think that it could be convenient that I open an issue in QtBug?
Thank you. -
-
@davidino said in Error "no matching member function for call to bindValue":
mDatabase(new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE"))),
albumDao(*mDatabase)This is wrong on so many levels.
First: don't store a QSqlDatabase member variable like explained in a warning in the QSqlDatabase documentation.
Second: even less as a pointer
Third: if you have to deference QSqlDatabase, it means you are already having issues in your design.Are you using only the default connection ? If so, then there's no need to pass anything around as it is the connection used when you don't pass any specific parameter to e.g. QSqlQuery.
If you have several different connections, then pass their name around so the classes concerned can all QSqlDatabase::database to get the correct connection to use. -
Hello SGaist and jonB,
thank you for messages. I open this post for the queryBind error (which is the one that I'm going to ask to QtBug), but I received many good advices. I've changed the code as follow:databaseManager:
#ifndef DATABASEMANAGER_H #define DATABASEMANAGER_H #include <QString> #include "albumdao.h" #include "picturedao.h" class QSqlDatabase; const QString DATABASE_FILENAME = "gallery.db"; class DatabaseManager { public: static DatabaseManager& instance(); ~DatabaseManager(); protected: DatabaseManager(const QString& path = DATABASE_FILENAME); DatabaseManager& operator=(const DatabaseManager& rhs); public: const QString mDataBasePath; const AlbumDao albumDao; const PictureDao pictureDao; }; #endif // DATABASEMANAGER_H #include "databasemanager.h" #include <QSqlDatabase> DatabaseManager &DatabaseManager::instance() { static DatabaseManager singleton; return singleton; } DatabaseManager::~DatabaseManager() { QSqlDatabase::database(mDataBasePath).close(); } DatabaseManager::DatabaseManager(const QString &path) : mDataBasePath(path), albumDao(path), pictureDao(path) { QSqlDatabase database = QSqlDatabase::addDatabase("QSQLITE", path); database.open(); // Called after opening database albumDao.init(); pictureDao.init(); }
albumDao:
#ifndef ALBUMDAO_H #define ALBUMDAO_H class QSqlDatabase; #include "album.h" #include <QList> class AlbumDao { public: explicit AlbumDao(QString database); void init() const; void addAlbum(Album& album) const; void updateAlbum(const Album& album) const; void removeAlbum(int id) const; QList<Album*> albums() const; private: QString mDatabaseName; }; #endif // ALBUMDAO_H #include "albumdao.h" #include <QSqlDatabase> #include <QSqlQuery> #include <QSql> #include <QVariant> #include <QDebug> #include "databasemanager.h" AlbumDao::AlbumDao(QString database) : mDatabaseName(database) { } void AlbumDao::init() const { QSqlDatabase database = QSqlDatabase::database(mDatabaseName); if (!database.tables().contains("albums")) { QSqlQuery query(database); query.exec("CREATE TABLE albums (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)"); } } void AlbumDao::addAlbum(Album &album) const { bool tempBool; QSqlDatabase database = QSqlDatabase::database(mDatabaseName); QSqlQuery query(database); tempBool=query.prepare("INSERT INTO albums (name) VALUES (:name)"); qDebug() << "prepare: " << tempBool << endl; query.bindValue(":name", album.name()); tempBool=query.exec(); qDebug() << "exec: " << tempBool << endl; album.setId(query.lastInsertId().toInt()); } void AlbumDao::updateAlbum(const Album &album) const { QSqlDatabase database = QSqlDatabase::database(mDatabaseName); QSqlQuery query(database); query.prepare("UPDATE albums SET name = (:name) WHERE id = (:id)"); query.bindValue(":name", album.name()); query.bindValue(":id", album.id()); query.exec(); //DatabaseManager::debugQuery(query); } void AlbumDao::removeAlbum(int id) const { QSqlDatabase database = QSqlDatabase::database(mDatabaseName); QSqlQuery query(database); query.prepare("DELETE FROM albums WHERE id = (:id)"); query.bindValue(":id", id); query.exec(); } QList<Album *> AlbumDao::albums() const { QSqlDatabase database = QSqlDatabase::database(mDatabaseName); QSqlQuery query("SELECT * FROM albums", database); query.exec(); QList<Album*> list; while(query.next()) { Album* album = new Album(); album->setId(query.value("id").toInt()); album->setName(query.value("name").toString()); list.append(album); } return list; }
Is it correct in this way?
Thank you. -
No, the second parameter is not the path to your database, it's the name of the connection.
-
Hello @SGaist,
thank you for your post I've changed as follow.DatabaseManager::DatabaseManager(const QString &connectionName) : mDataBaseName(connectionName), albumDao(connectionName), pictureDao(connectionName) { QSqlDatabase database = QSqlDatabase::addDatabase("QSQLITE", connectionName); // Database path database.setDatabaseName(connectionName + ".dB"); database.open(); // Called after opening database albumDao.init(); pictureDao.init(); }
Thank you again for your always helpful advice. I'll ask to QtBug regarding the Semantic error with "bindValue"