2

For example, the following snippet do these things: First reading data from database, then transform the data, and last write results back to database. More specifically:

  1. Read data from database and store them into class A record by record.
  2. Transform data stored in class A record by record, class B do this job.
  3. Store all the results in QVariantList and batch write them into ihe database.

The problem is tight couple between the class A, class B and class ReadTransWrite if I want to add a member variable A4 into class A, 3 classes need to be changed. see the comment begin with "//-->"

How to decouple? Any pattern would be recommended? Any suggestion?

Snippet:

class A {
public: 
    void trans(QSqlQuery query){
        A1 = query.record().field("A1").value().toString();
        A2 = query.record().field("A2").value().toDate();
        A3 = query.record().field("A3").value().toInt();
        //--> A4 = query.record().field("A4").value().toDouble();
    }
public:
    QString A1;
    QDate A2;
    int A3;
    //--> double A4;
};

class B {
public:
    void trans(const A& a){
        B1 = A1;
        B2 = A2;
        B3 = A3;
        //--> B4 = A4;
    }
public:
    QString B1;
    QDate B2;
    int B3;
    //--> double B4;
};

class ReadTransWrite {
.....
    void do();
.....
}

void ReadTransWrite::do(){
    ....
    // prepare for batch insert into the database
    QVariantList B1s;
    QVariantList B2s;
    QVariantList B3s;
    //--> QVariantList B4s;

    A a;  // read record by record from data base
    B b;  // transform the results record by record

    QString sql_read = "select A1, A2, A3 from table0";
    //--> QString sql_read = "select A1, A2, A3, A4 from table0";
    QSqlQuery query_read;
    query_read.exec(sql_read);
    while(query_read.next()){
        a.trans(query_read);    // read record by record from data base
        b.trans(a);             // transform the results record by record
        B1s.push_back(b.B1);
        B2s.push_back(b.B2);
        B3s.push_back(b.B3);
        //--> B4s.push_back(b.B4);
    }

    QSqlQuery query_write;
    QString sql_write = "insert into table (B1, B2, B3) values (:B1, :B2, :B3)";
    //--> QString sql_write = "insert into table (B1, B2, B3, B4) values (:B1, :B2, :B3, :B4)";
    query_write.prepare(sql_write);

    query_write.bindValue(":B1",B1s);
    query_write.bindValue(":B2",B2s);
    query_write.bindValue(":B3",B3s);
    //--> query_write.bindValue(":B4",B4s);

    query_write.execBatch();
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
rage
  • 21
  • 2
  • 1
    `A1 = query.record().field("A1").value().toString();` -- srsly? [Law Of Demeter](http://en.wikipedia.org/wiki/Law_of_Demeter) – sehe Nov 27 '12 at 11:08
  • If things like "database", "table" and "field" are business objects in your application, then such things are almost inevitable. If your business objects are more like "customer", "supplier" and "order", and the database is strictly their persistence mechanism, then chances are that nobody outside of `class Customer` ever or needs to see tables or fields pertaining to the customer data type. Just a thought. – n. m. could be an AI Nov 27 '12 at 11:40
  • @sehe pls forgive me for ignorance of 'Law of Demeter', thank's for Tim's reminder. yes, great point – rage Nov 28 '12 at 05:51
  • unfortunately, I think it looks more like the first case, but the second case you metioned is very helpful, thank you @n.m. – rage Nov 28 '12 at 05:58

1 Answers1

0

You could make class A like that:

#include <QtCore/QVariant>
#include <QtSql/QSqlRecord>

class A 
{
public: 
    void fillFromRecord( const QSqlRecord& record )
    {
        for( int iColumn = 0; iColumn < record.count(); iColumn++ )
        {
            _contentMap.insert( 
                record.fieldName( iColumn ), 
                record.value( iColumn )
                );
        }
    }

    inline QVariantMap getContentMap() const { return _contentMap; }

private:
    QVariantMap _contentMap;
};

Note: I did not test that code for compile errors but it should give you a general idea at least.


That way class A will never change whenever the database changes.

Also note how you can just ask for the QSqlRecord rather than the QSqlQuery to work more towards the Law of Demeter which sehe linked in the comment.

You can change the type of the map for your needs, for example a QHash< int, QVariant > which only stores the column indices rather than the names and does not require the extra QMap functionality (sorting basically) might be sufficient as well.

Tim Meyer
  • 12,210
  • 8
  • 64
  • 97