0

I am willing to store objects in a database. The purpose is to be able to read / write these objects with the program. The requirements are the following:

  • Objects can be complex using Qt classes such as QList, QString ... or even can contain other objects that use QObjects
  • The database should not be readable or modified by human (no text file, and if I use sqlite database, it has to be encrypted in a way)
  • I should be able to remove, read an object by its name and count the number of objects in the database, without loading everything in the memory

I asked a question here, to do this with a QDataStream with a minimalist example. But it seems it is not the best way to proceed. Would you have some suggestions regarding the solutions that exist for this purpose?

I have tried the following but it does not fulfill the requirements:

  • Storing text in sqlite with QtSQL: but the data is accessible by using sqlitemanager for example, can be modified or removed by humans. Moreover, I have no idea regarding the way to store QList for example or other objects that I created and contain QObject (for example, 2 QList)
  • Storing binary data using QDataStream: in this case, I cannot count the number of objects in my file, neither read or remove a specific object without loading the entire file in memory.

I would be grateful if you could give me some suggestions or provide example, even if the example is minimalist.

froz
  • 163
  • 1
  • 12
  • You might be interested in [this question](https://stackoverflow.com/questions/5669905/sqlite-with-encryption-password-protection) – Igor Tandetnik Feb 11 '20 at 14:50
  • Thank you Igor, I already found it. This could be a way to store data in SQLite database and crypt them. However, I do not know how to write a QList in SQL db. – froz Feb 11 '20 at 15:06
  • Normally, you would design a proper database schema and implement proper object-relational mapping (ORM). But if you are looking for shortcuts, anything you could serialize into a binary stream, you could store as a blob in a database. – Igor Tandetnik Feb 11 '20 at 15:12
  • If I understand correctly, and if I consider the example that I wrote her: https://stackoverflow.com/questions/60162120/reading-specific-object-in-qdatastream-and-count-number-of-objects-stored it means I store, for example, the User name in a column of SQLite and a QDataStream (binary serialization of my class object) in the second column ? I think it is a very good idea! – froz Feb 11 '20 at 15:33

1 Answers1

0

I finally found a solution, especially thanks to Igor Tandetnik and thanks to the topic here

I haven't quite finalized, there is a small imperfection because I have to define an object of my user class that I don't use in order to call the readFromDB function to generate my object from the db.

On the other hand, I get this error message "QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed" each time I call my database.

Anyway, it's a bit late now, and I think it might help some people so I post this minimalist imperfect code below. I'll post an update in the next few days.

Thanks again.

#include "QString"
#include "QFile"
#include "QDataStream"
#include "qdebug.h"
#include "QtSql"
#include "QSqlDatabase"
#include "qmessagebox.h"

class User
{
protected:
QString name;
QList<QString> childrens;

public:
QString getName(){ return name;}
QList<QString> getChildrens(){ return childrens;}

void setName(QString x) {name = x;}
void setChildrens(QList<QString> x) {childrens = x;}



friend QDataStream &operator<<(QDataStream &out, const User &t)
{
    out << t.name << t.childrens;
    return out;
}

friend QDataStream &operator>>(QDataStream &in, User &t)
{
    QString inname;
    QList<QString> inchildrens;
    in >> inname >> inchildrens;
    t.name = inname;
    t.childrens = inchildrens;
    return in;
}
QByteArray object2blob( const User& user )
{
  QByteArray result;
  QDataStream bWrite( &result, QIODevice::WriteOnly );
  bWrite << user;

  return result;

}
User blob2object( const QByteArray& buffer )
{
  User result;
  QDataStream bRead( buffer );
  bRead >> result;

  return result;
}
int saveToDB( const User& user )
{
    QSqlDatabase myDB = QSqlDatabase::addDatabase("QSQLITE");
    myDB.setDatabaseName( "file.db");
    if (!myDB.open())
    {
        qDebug()<<"Failed to open SQL database of registered users";
    }
    else
    {
        qDebug()<<"Successfully opening SQL database of registered users";
        QSqlQuery query;

        query.prepare( "CREATE TABLE IF NOT EXISTS users (name TEXT, childrens BLOB)" );
          if( !query.exec() )
          {
            qDebug() << query.lastError();
          }
          else
          {
            qDebug() << "Table created!";
            query.prepare( "INSERT INTO users (name,childrens) VALUES (:name,:childrens)" );
            query.bindValue(":name", name);
            query.bindValue( ":childrens",  object2blob(user) );
            query.exec();
          }
        query.clear();
        myDB.close();
    }
    QSqlDatabase::removeDatabase("UserConnection");

    return 0;
}
User readFromDB( QString name )
{
    User result;
    QSqlDatabase myDB = QSqlDatabase::addDatabase("QSQLITE");
    myDB.setDatabaseName( "file.db");
    if (!myDB.open())
    {
        qDebug()<<"Failed to open SQL database of registered users";
    }
    else
    {
        QSqlQuery query;

        query.prepare( "SELECT * FROM users WHERE name ='"+ name +"'" );
        //query.bindValue( 0, name );

        if ( query.exec() && query.next() ) {
          result = blob2object( query.value( 1 ).toByteArray() );
        }
        query.clear();
        myDB.close();
    }
    QSqlDatabase::removeDatabase("UserConnection");
    qDebug()<<result.getChildrens();
    return result;
}
};


////////////////////////////////////////////////////////////////
int main()
{
    User u;
    u.setName("Georges");
    u.setChildrens(QList<QString>()<<"Jeanne"<<"Jean");
    u.saveToDB(u);

    User v;
    v.setName("Alex");
    v.setChildrens(QList<QString>()<<"Matthew");
    v.saveToDB(v);

    User w;
    w.setName("Mario");
    w.saveToDB(w);

    User to_read; //to improve here
    User a = to_read.readFromDB("Georges");

    qDebug()<<a.getChildrens();
    return 0;
}
froz
  • 163
  • 1
  • 12