2013-02-15 2 views
3

sqlite 데이터베이스와의 모든 데이터를 처리해야하는 클래스를 만들려고합니다. 그러나 나는 QT와 C++에 대해 매우 익숙하며 클래스의 데이터베이스 객체 선언에 대해 궁금해합니다. 나는 옳고 그름을하고 있으며 어떻게 정상적으로 수행되어야하는지, 할 수 있는지에 대한 몇 가지 팁을 필요로 할 수 있습니다. 내 목표는 클래스에 대한 단일 QSqlDatabase를 만들고 클래스 내의 모든 함수에 사용하는 것이 었습니다. 순간Qt : 클래스의 QSqlDatabase 객체 (선언 방법)

, 나는 다음과 같은 코드가 있습니다

MAIN.CPP

#include "mainwindow.h" 
#include "database.h" 
#include <QApplication> 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 

    Database db; 
    MainWindow w; 

    if(db.createStructure()) 
    { 
     w.show(); 
    } 

    return a.exec(); 
} 

database.h

#ifndef DATABASE_H 
#define DATABASE_H 

#include <QObject> 
#include <QSqlDatabase> 

class Database : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit Database(QObject *parent = 0); 

    // FUNCTIONS 
    bool createStructure(); 

signals: 

public slots: 

private: 
    // VARIABLES 
    QSqlDatabase m_db; 

    // FUNCTIONS 
    bool open(); 
    void close(); 
    bool transaction(); 
    bool commit(); 
}; 

#endif // DATABASE_H 

database.cpp

#include "database.h" 
#include <QCoreApplication> 
#include <QSqlDatabase> 
#include <QSqlQuery> 
#include <QSqlError> 
#include <QList> 

Database::Database(QObject *parent) : 
    QObject(parent) 
{ 
    m_db = QSqlDatabase::addDatabase("QSQLITE"); 
    m_db.setHostName("localhost"); 
    m_db.setDatabaseName(QCoreApplication::applicationDirPath() + "/events.db"); 
} 

// PRIVATE 

bool Database::open() 
{ 
    return m_db.open(); 
} 

void Database::close() 
{ 
    return m_db.close(); 
} 

bool Database::transaction() 
{ 
    return m_db.transaction(); 
} 

bool Database::commit() 
{ 
    return m_db.commit(); 
} 

// PUBLIC 

bool Database::createStructure() 
{ 
    bool prepared; 
    QList<QString> commands; 

    commands.append("CREATE TABLE...;"); 
    commands.append("CREATE TABLE...;"); 
    commands.append("CREATE TABLE...;"); 

    if (!Database::open()) 
    { 
     return false; 
    } 
    else 
    { 
     if (!Database::transaction()) 
     { 
      Database::close(); 
      return false; 
     } 
     else 
     { 
      foreach(QString command, commands) 
      { 
       QSqlQuery query; 
       prepared = query.prepare(command); 

       if(!prepared) 
       { 
        if (!Database::commit()) 
        { 
         Database::close(); 
         return false; 
        } 
        else 
        { 
         Database::close(); 
         return false; 
        } 
       } 
       else 
       { 
        if(!query.exec()) 
        { 
         if (!Database::commit()) 
         { 
          Database::close(); 
          return false; 
         } 
         else 
         { 
          Database::close(); 
          return false; 
         } 
        } 
       } 
      } 

      if (!Database::commit()) 
      { 
       Database::close(); 
       return false; 
      } 
      else 
      { 
       Database::close(); 
       return true; 
      } 
     } 
    } 
} 

이 코드를 일하고있다.

그러나, QSQLITE 데이터베이스는 m_db 객체에 대한 하나의 시간을 추가하지 않고, 모든 시간은 클래스의 함수를 호출 때문에 ...

Database::Database(QObject *parent) : 
    QObject(parent) 
{ 
    m_db = QSqlDatabase::addDatabase("QSQLITE"); 
    m_db.setHostName("localhost"); 
    m_db.setDatabaseName(QCoreApplication::applicationDirPath() + "/events.db"); 
} 

은 ... 코드 블록마다 실행됩니다 시각. 현재 기본 연결이 바뀌 었습니다. 새 연결이 동일하기 때문에 프로그램에 아무런 영향도 미치지 않지만 깔끔한 솔루션처럼 보이지는 않습니다.

그래서 나는 한 번 MAIN.CPP에서 호출 할 수있는 선언 기능이 코드 블록 ...

MAIN.CPP을 대체하려고

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 

    Database db; 
    MainWindow w; 

    db.declare(“QSQLITE”, “localhost”, QCoreApplication::applicationDirPath() + "/events.db"); 

    if(db.createStructure()) 
    { 
     w.show(); 
    } 

    return a.exec(); 
} 

database.cpp

void Database::declare(QString driver, QString host, QString path) 
{ 
    m_db = QSqlDatabase::addDatabase(driver); 
    m_db.setHostName(host); 
    m_db.setDatabaseName(path); 
} 

...하지만 m_db 객체의 값은 물론 declare-function 내에서만 사용할 수 있으며 나중에 호출하는 다른 함수에서는 사용할 수 없습니다.

MAIN.CPP

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 

    QSqlDatabase qdb = QSqlDatabase::addDatabase("QSQLITE"); 
    qdb.setHostName("localhost"); 
    qdb.setDatabaseName(QCoreApplication::applicationDirPath() + "/events.db"); 

    Database db; 
    MainWindow w; 

    if(db.createStructure(qdb)) 
    { 
     w.show(); 
    } 

    return a.exec(); 
} 

database.cpp

:

솔루션에 대한 나의 추측은 MAIN.CPP에 QSqlDatabase를 선언하고 호출해야하는 함수에 제공하는 것

bool Database::open(QSqlDatabase qdb) 
{ 
    return qdb.open(); 
} 

void Database::close(QSqlDatabase qdb) 
{ 
    return qdb.close(); 
} 

bool Database::transaction(QSqlDatabase qdb) 
{ 
    return qdb.transaction(); 
} 

bool Database::commit(QSqlDatabase qdb) 
{ 
    return qdb.commit(); 
} 

bool Database::createStructure(QSqlDatabase qdb) 
{ 
    bool prepared; 
    QList<QString> commands; 

    commands.append("CREATE TABLE...;"); 
    commands.append("CREATE TABLE...;"); 
    commands.append("CREATE TABLE...;"); 

    if (!Database::open(qdb)) 
    { 
     return false; 
    } 
    else 
    { 
     if (!Database::transaction(qdb)) 
     { 
      Database::close(qdb); 
      return false; 
     } 
     else 
     { 
      foreach(QString command, commands) 
      { 
       QSqlQuery query; 
       prepared = query.prepare(command); 

       if(!prepared) 
       { 
        if (!Database::commit(qdb)) 
        { 
         Database::close(qdb); 
         return false; 
        } 
        else 
        { 
         Database::close(qdb); 
         return false; 
        } 
       } 
       else 
       { 
        if(!query.exec()) 
        { 
         if (!Database::commit(qdb)) 
         { 
          Database::close(qdb); 
          return false; 
         } 
         else 
         { 
          Database::close(qdb); 
          return false; 
         } 
        } 
       } 
      } 

      if (!Database::commit(qdb)) 
      { 
       Database::close(qdb); 
       return false; 
      } 
      else 
      { 
       Database::close(qdb); 
       return true; 
      } 
     } 
    } 
} 

다시 사용할 수있는 QSqlDatabase 개체를 클래스에 저장할 수 있습니까? 그렇다면 어떻게? 정말 감사드립니다!

EDIT 1

내가있는 기능을 사용하고 디자이너에서 생성 된 일부 코드입니다.

void MainWindow::on_pushButton_24_clicked() 
{ 
    Database db; 
    bool b = db.createStructure(); 

    QMessageBox::information(this, "test", QString(b)); 
} 
+0

이것은별로 의미가 없습니다. _how_ 데이터베이스 클래스를 사용하고 있음을 표시하십시오. 사용하도록 설계된 것처럼 사용하지 않는 것 같습니다. – Mat

+0

데이터베이스 클래스는 신호와 슬롯에있는 gui 프로그램에 사용됩니다. 버튼을 클릭하십시오 -> 데이터베이스 마술을하십시오. 디자인 할 때 이미 코드를 망칠 가능성은 완전히 있습니다. 나는 당신이 "당신이 그것을 어떻게 사용하는지 보여준다"는 것이 무엇을 의미하는지 정말로 확신하지 못합니다. 그것은 실행될 수있는 데이터베이스 기능을 가진 클래스 일뿐입니다. : -/ – Endauriel

+0

Database 클래스를 사용하는 일부 코드를 보여줍니다. – Mat

답변

1

내가 설명을 위해 원래의 코드에 충실 것

mainwindows.cpp .


면책 조항 : 내가 구문 오류가있는 경우 용서, 내 제안 중 하나를 컴파일하지 않았다.

당신은 아마 찾고있는 모든

먼저, (난 더 이상 그 정도별로 좋아하지 않아요, 그러나 당신의 목적을 위해 하나가 적절한 것으로 간주 될 수 있음을 주장 할 수 있음) Singleton Pattern입니다 :

class Database : public QObject 
{ 
    Q_OBJECT 

public: 
    static Database* instance(); 
private: 
    static Database* m_instance; 
    Database(); 
    ~Database() {}; // it can be necessary to have this public in some cases, if 
        // you ever get a linker error related to deletion, this is 
        // probably the reason. 

public: 

    // FUNCTIONS 
    ... 
}; 

그리고 당신의 .cpp 파일에 다음과 같은 :

당신은 당신의 클래스 정의에 다음이 있어야3210

예를 들어 다음을 사용하여 해당 싱글 톤에 액세스 할 수 있습니다.

if(Database::instance()->createStructure()) 
{ 
    w.show(); 
} 

이것은 무엇입니까? 프로그램의 시작, 라인 NULL로 m_instance 변수 값을 처음

Database* Database::m_instance = NULL; 

에서. 처음으로 Database::instance()을 호출하면 m_instance가 여전히 NULL이고 새 개체가 만들어지고 m_instance이 해당 개체를 가리킨다는 것을 알게됩니다. 그 시점부터 해당 객체에 대한 포인터가 항상 반환되지만 더 이상 Database 객체가 생성되지 않습니다. 오류가있을 경우에도 귀하의 createStructure() 기능에


당신은 당신의 데이터베이스를 commit(). 일반적인 절차는 성공시 commit()이고 실패시 rollback()입니다. 것을 고정하기 전에,하지만 다음 포인트를 읽으십시오 : 내가 추천 할 것입니다


세 번째 것은이 같은 라인을 여러 번 많이 볼 때마다 의심스러운 것에 익숙해있다. 그것은 일반적으로 하위 기능을 요구합니다.

bool Database::createStructure() 
{ 
    QStringList commands; 

    commands.append("CREATE TABLE...;"); 
    commands.append("CREATE TABLE...;"); 
    commands.append("CREATE TABLE...;"); 

    if (!Database::open()) return false; 

    // at this point you can be sure the database is open 

    if (!Database::transaction()) 
    { 
     Database::close(); 
     return false; 
    } 

    // at this point you can be sure the database is open and a transaction was started 

    if (!Database::executeCommands(commands)) 
    { 
     // an error occurred - we need to rollback what we did so far 
     Database::rollback(); 
     Database::close(); 
     return false; 
    } 

    // everything was executed properly, but the transaction is still active 
    // => commit the changes we've made 
    bool committed = Database::commit(); 

    // no matter if the commit was successful or not, close the database, 
    // then return the result we've stored 
    Database::close(); 
    return committed; 
} 

bool Database::executeCommands(const QStringList& commands) 
{ 
    // This method simply executes the queries and is relieved from 
    // transaction-related code. 

    foreach(QString command, commands) 
    { 
     QSqlQuery query; 
     bool prepared = query.prepare(command); 

     if(!prepared) return false; 

     if(!query.exec()) return false;   
    } 
    return true; 
} 

이 될 수있다 :

나는 다른 방법을 도입하고 필요하지 어디에 else{ }을 떠나하여 createStructure() 방법을 재 작성 방법을 살펴에 대한

Database::close(); 
return false; 

을 말하는거야 추가 리팩터링을하면 코드를 따르기 쉽고 오류가 발생하기 쉽다는 예일뿐입니다.

+0

완벽하게 제 질문에 답변하고 제 코드의 가독성을 향상시킬 수있는 통찰력을주었습니다. 당신 말이 맞아요,저기서 너무 많은 진술을했습니다 ... 그렇게 잘 보입니다. 나는 아직도 "Database :: commit()"에 대해 약간 혼란 스럽다. 이것이 true를 반환하면 자동으로 모든 명령이 실행되었음을 의미합니까? 명령을 실행하는 과정에서 오류가 발생하면 커밋 문에 도달하지 않을 것입니다. false를 반환 할 것이기 때문입니다. 그러나 그 코드의 어떠한 상황에서도 위탁이 거짓으로 돌아갈 수 있습니까? – Endauriel