Seite 1 von 2
[solved] querys in mehreren Klassen
Verfasst: 2. April 2008 10:22
von C167
Tagchen, ich hab hier in meiner Hauptklasse ein QSqlDatabase-Objekt angelegt, das ich per Parameter an den Konstruktor einiger Klassen weitergebe. Das stammt noch aus der Zeit, als ich mehr als eine Datenbank gleichzeitig genutzt hab. Vorher ging alles, da hab ich fuer jede der SQLite-Datenbanken ein Objekt mit eigenem Namen erstellt und dann an die Klassen weitergegeben. die haben per
die Querys abgesendet. Nun uebergebe ich jeder Klasse das gleiche Objekt.
Das Resultat ist, dass nun nur noch eine der Klassen die Datenbank nutzen kann (aber nicht die erste, die instanziiert wird). Alle anderen Klassen geben Fehler von sich, bisweilen wird das Programm auch per SegFault terminiert.
und am Ende, nachdem alle Klassen ihre Daten geladen haben (bzw es versucht haben), feuert das Programm das hier:
Code: Alles auswählen
QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
Ich hab nun versucht, das Query-Objekt mit clean() freizugeben, aber das aendert leider garnichts.
Was mach ich da falsch?
Laut Anleitung kann man sich ja einfach per
ein Datenbankobjekt holen, wenn man nur eine einzige DB verwendet. Aber waere das dann noetig, ein Objekt in der Klasse zu halten? Muesste es nicht reichen, einfach seine Querys abzusenden?
C167
Verfasst: 2. April 2008 10:40
von Christian81
Wie Du schon gesagt hast - einfach QSqlDatabase::database("name") benutzen und fertig.
Verfasst: 2. April 2008 10:44
von solarix
bisweilen wird das Programm auch per SegFault terminiert.
Hast du Multithreading?
Verfasst: 2. April 2008 11:17
von C167
Christian81 hat geschrieben:Wie Du schon gesagt hast - einfach QSqlDatabase::database("name") benutzen und fertig.
Was nur leider nicht funktioniert. exec() gib true, next() aber false bei einem Select-Statement.
solarix hat geschrieben:
bisweilen wird das Programm auch per SegFault terminiert.
Hast du Multithreading?
Ich hab zwar mehrere Prozessoren, aber ich verwende keine Threads
Verfasst: 2. April 2008 11:20
von Christian81
Da es bei jedem anderen funktioniert nur nicht bei Dir würde ich sagen der Fehler liegt bei Dir. Etwas Code ist ggf. hilfreich.
Vielleicht bringt das select ja auch nichts zurück !?
Verfasst: 2. April 2008 11:32
von C167
Datenbankverbindung, Ausschnitt hauptklasse:
Code: Alles auswählen
// h
class mainclass:public QMainWindow
{
Q_OBJECT
public:
mainclass();
bool init();
~mainclass();
private:
bool initDatabase();
// Main Content
QStackedWidget *stack;
MainPage *mainPage;
// Databases
QSqlDatabase db;
};
#endif
// cpp
bool mainclass::initDatabase()
{
QString dbFile ( QDir::currentPath() +"/../libQObject.dll" );
if ( QFile::exists ( dbFile ) )
{
db = QSqlDatabase::addDatabase ( "QSQLITE" );
db.setDatabaseName ( dbFile );
if ( db.open() )
{
return true;
}
}
return false;
}
void mainclass::createUi()
{
setGeometry ( 100, 100, 1024, 768 );
setSizePolicy ( QSizePolicy::Ignored, QSizePolicy::Expanding );
stack = new QStackedWidget ( this );
setCentralWidget ( stack );
// Main Page
mainPage = new MainPage ( db, stack );
mainPage->init();
stack->addWidget ( mainPage );
}
mainpage
Code: Alles auswählen
//h
class MainPage : public QWidget
{
Q_OBJECT
public:
MainPage ( QSqlDatabase db, QWidget *parent = 0 );
bool init();
~MainPage();
public slots:
void changeSplash ( QAction* );
protected:
void resizeEvent ( QResizeEvent * );
QImage getImage ( int );
private:
QSqlDatabase db;
QStackedLayout *stack;
QLabel *splash0;
QLabel *splash1;
QLabel *splash2;
QLabel *splash3;
QLabel *splash4;
QWidget *w0;
QWidget *w1;
QWidget *w2;
QWidget *w3;
QWidget *w4;
QVBoxLayout *l0;
QVBoxLayout *l1;
QVBoxLayout *l2;
QVBoxLayout *l3;
QVBoxLayout *l4;
QPixmap *p0;
QPixmap *p1;
QPixmap *p2;
QPixmap *p3;
QPixmap *p4;
};
#endif
//cpp
MainPage::MainPage ( QSqlDatabase db, QWidget *parent )
: QWidget ( parent )/*, db ( db )*/
{
db = QSqlDatabase::database();
setSizePolicy ( QSizePolicy::Ignored, QSizePolicy::Ignored );
stack = new QStackedLayout ( this );
setLayout ( stack );
w0 = new QWidget ( this );
l0 = new QVBoxLayout ( w0 );
w0->setLayout ( l0 );
w1 = new QWidget ( this );
l1 = new QVBoxLayout ( w1 );
w1->setLayout ( l1 );
w2 = new QWidget ( this );
l2 = new QVBoxLayout ( w2 );
w2->setLayout ( l2 );
w3 = new QWidget ( this );
l3 = new QVBoxLayout ( w3 );
w3->setLayout ( l3 );
w4 = new QWidget ( this );
l4 = new QVBoxLayout ( w4 );
w4->setLayout ( l4 );
splash0 = new QLabel ( w0 );
splash0->setMaximumSize ( splash0->maximumSize() );
splash1 = new QLabel ( w1 );
splash2 = new QLabel ( w2 );
splash3 = new QLabel ( w3 );
splash4 = new QLabel ( w4 );
l0->addWidget ( splash0 );
l1->addWidget ( splash1 );
l2->addWidget ( splash2 );
l3->addWidget ( splash3 );
l4->addWidget ( splash4 );
stack->addWidget ( w0 );
stack->addWidget ( w1 );
stack->addWidget ( w2 );
stack->addWidget ( w3 );
stack->addWidget ( w4 );
w0->setSizePolicy ( QSizePolicy::Expanding,QSizePolicy::Expanding );
}
bool MainPage::init()
{
p0 = new QPixmap ( QPixmap::fromImage ( getImage ( 0 ) ) );
splash0->setPixmap ( ( *p0 ).scaled ( QSize ( 930, 762 ), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
p1 = new QPixmap ( QPixmap::fromImage ( getImage ( 1 ) ) );
splash1->setPixmap ( ( *p1 ).scaled ( QSize ( 930, 762 ), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
p2 = new QPixmap ( QPixmap::fromImage ( getImage ( 2 ) ) );
splash2->setPixmap ( ( *p2 ).scaled ( QSize ( 930, 762 ), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
p3 = new QPixmap ( QPixmap::fromImage ( getImage ( 3 ) ) );
splash3->setPixmap ( ( *p3 ).scaled ( QSize ( 930, 762 ), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
p4 = new QPixmap ( QPixmap::fromImage ( getImage ( 4 ) ) );
splash4->setPixmap ( ( *p4 ).scaled ( QSize ( 930, 762 ), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
return true;
}
QImage MainPage::getImage ( int id )
{
qDebug() << id;
QSqlQuery query /*( db )*/;
query.prepare ( "SELECT data FROM splashes WHERE id = :id" );
query.bindValue ( ":id", id+1 );
// if ( !query.exec() ) return QImage();
// if ( !query.next() ) return QImage();
qDebug() << query.exec() << " " /*<< query.next()*/ << " " << query.executedQuery() << " " << query.lastError();
QByteArray array = query.value ( 0 ).toByteArray();
QBuffer buffer ( &array );
buffer.open ( QIODevice::ReadOnly );
QImageReader reader ( &buffer, "JPG" );
QImage image = reader.read();
return image;
}
MainPage::~MainPage()
{
}
Die Datenbank hat eine Tabelle "splashes" mit einem blob-Feld data. Ich habe nach der Umstellung nur den Tabellennamen geaendert.
Logausgabe:
Code: Alles auswählen
0
true "SELECT data FROM splashes WHERE id = ?" QSqlError(-1, "", "")
QSqlQuery::value: not positioned on a valid record
QPixmap::scaled: Pixmap is a null pixmap
1
true "SELECT data FROM splashes WHERE id = ?" QSqlError(-1, "", "")
QSqlQuery::value: not positioned on a valid record
QPixmap::scaled: Pixmap is a null pixmap
2
true "SELECT data FROM splashes WHERE id = ?" QSqlError(-1, "", "")
QSqlQuery::value: not positioned on a valid record
QPixmap::scaled: Pixmap is a null pixmap
3
true "SELECT data FROM splashes WHERE id = ?" QSqlError(-1, "", "")
QSqlQuery::value: not positioned on a valid record
QPixmap::scaled: Pixmap is a null pixmap
4
true "SELECT data FROM splashes WHERE id = ?" QSqlError(-1, "", "")
QSqlQuery::value: not positioned on a valid record
QPixmap::scaled: Pixmap is a null pixmap
{gleicher Fehler in den anderen Klassen bis auf einer}
QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
Verfasst: 2. April 2008 11:39
von Christian81
Du benutzt nicht QSqlQuery(QSqlDatabase) - deshalb wird die default-DB benutzt ich würde mal der DB-connection einen Namen geben damit Du sicher bist auf der richtigen DB zu sein.
Verfasst: 2. April 2008 11:41
von solarix
und
Code: Alles auswählen
MainPage::MainPage ( QSqlDatabase db, QWidget *parent )
: QWidget ( parent )/*, db ( db )*/
{
db = QSqlDatabase::database();
Macht nicht das, was du denkst...
Verfasst: 2. April 2008 11:46
von C167
Christian81 hat geschrieben:Du benutzt nicht QSqlQuery(QSqlDatabase) - deshalb wird die default-DB benutzt ich würde mal der DB-connection einen Namen geben damit Du sicher bist auf der richtigen DB zu sein.
Ich hab ja nur die eine Datenbank, auf die alle Klassen zugreifen. einen Namen brauche ich ja laut Anleitung nur, wenn ich mehrere Verbindungen zu mehreren Datenbanken hab weil die Klassen sonst nicht wissen, welche DB sie nun verwenden sollen
solarix hat geschrieben:
und
Code: Alles auswählen
MainPage::MainPage ( QSqlDatabase db, QWidget *parent )
: QWidget ( parent )/*, db ( db )*/
{
db = QSqlDatabase::database();
Macht nicht das, was du denkst...
Aehm. das verwundert mich jetzt. Ich dachte, ich lege ein Objekt an und fuelle es im Konstruktor mit Leben um es spaeter weiterzuverwenden. Ich lege ja auch eine int-Variable im Header an und befuelle sie per = {Wert}.
Verfasst: 2. April 2008 12:01
von solarix
Das dachte ich mir bereits..
Ich weiss nicht, ob es dein Problem löst (QSqlQuery sollte -wie mehrfach diskutiert- die Standard-Connection nehmen), aber achte trotzdem mal darauf, wieviele unterschiedliche Variabeln "db" du im Konstruktor zur Verfügung hast..
Verfasst: 2. April 2008 12:06
von C167
Au verdammt, da hast du recht.
Ich hab jetzt mal
gemacht, aber es geht trotzdem nicht
Verfasst: 2. April 2008 12:12
von Christian81
Hau endlich deine Klassenvariable weg, nimm einen Namen und fertig!
Verfasst: 2. April 2008 12:18
von solarix
Ausserdem:
Code: Alles auswählen
QString dbFile ( QDir::currentPath() +"/../libQObject.dll" );
if ( QFile::exists ( dbFile ) )
{
db = QSqlDatabase::addDatabase ( "QSQLITE" );
db.setDatabaseName ( dbFile );
Ich habe noch nie mit QSQLITE gearbeitet, aber stimmt das so (mit der DLL als Angabe in "setDatabaseName()")?
Verfasst: 2. April 2008 13:18
von C167
solarix hat geschrieben:Ausserdem:
Code: Alles auswählen
QString dbFile ( QDir::currentPath() +"/../libQObject.dll" );
if ( QFile::exists ( dbFile ) )
{
db = QSqlDatabase::addDatabase ( "QSQLITE" );
db.setDatabaseName ( dbFile );
Ich habe noch nie mit QSQLITE gearbeitet, aber stimmt das so (mit der DLL als Angabe in "setDatabaseName()")?
Ja sicher, es ist prinzipiell egal welche Namen die hat. Sinn dahinter ist, dass man unter Windows die Datenbank nicht sofort als solche erkennen kann. Mit dem Namen kann man sie nicht unbedingt von den anderen Qt-Bibliotheken unterscheiden.
Christian81 hat geschrieben:Hau endlich deine Klassenvariable weg, nimm einen Namen und fertig!
Okay, ich hab die Uebergabe aus dem Konstruktor entfernt, die Member-Variable und und und. Die anderen Klassen, die auf die Datenbank zugreifen sind auskommentiert. Es wird also eine Verbindung zur Datenbank aufgebaut und dannach der Konstruktor der MainPage aufgerufen, der nun nur den parent enthaellt. Das einzige Vorkommen von Datenbanken ist jetzt die eine Methode getImage(int):
Code: Alles auswählen
QImage MainPage::getImage ( int id )
{
qDebug() << id;
QSqlQuery query ( QSqlDatabase::database() );
query.prepare ( "SELECT data FROM splashes WHERE id = :id" );
query.bindValue ( ":id", id+1 );
qDebug() << query.exec() << " " << query.next() << " " << query.executedQuery() << " " << query.lastError();
QByteArray array = query.value ( 0 ).toByteArray();
QBuffer buffer ( &array );
buffer.open ( QIODevice::ReadOnly );
QImageReader reader ( &buffer, "JPG" );
QImage image = reader.read();
return image;
}
Das funktioniert schonmal nicht. Ich finde es sehr verwirrend, dass exec ein true zurueckliefert, next aber ein false.
Executes the SQL in query. Returns true and sets the query state to active if the query was successful; otherwise returns false.
Also stimmt das Query. Wenn ich exakt das gleiche Query per Hand an die Datenbank uebergebe, kommen wie erwartet Binaerzeichen raus.
Also geben wir dem Kind einen Namen. addDatabase() hat den Parameter "MainDB" bekommen, ebenso wie QSqlDatabase::database(). Wieder der gleiche Fehler.
Also den Konstruktor in
Code: Alles auswählen
MainPage::MainPage ( QSqlDatabase db_conn, QWidget *parent )
geaendert und per
das ganze (hoffentlich) in die Member-Variable gepackt. Keine Aenderung.
Naechster Versuch: ohne ueberhabe mit = sondern stattdessen
Code: Alles auswählen
MainPage::MainPage ( QSqlDatabase db_conn, QWidget *parent )
: QWidget ( parent ) , db ( db_conn )
und wie immer im log:
0
true false "SELECT data FROM splashes WHERE id = ?" QSqlError(-1, "", "")
QSqlQuery::value: not positioned on a valid record
QPixmap::scaled: Pixmap is a null pixmap
Verfasst: 2. April 2008 14:01
von solarix
es ist prinzipiell egal welche Namen die hat.
Security by Obscurity .. meiner Meinung nach unsinnig.
Code: Alles auswählen
Debug() << query.exec() << " " << query.next() << " " << query.executedQuery() << " " << query.lastError();
Die Reihenfolge der Auswertung der Operanden ist in C++ undefiniert (d.h. der Compiler kann da tun was er möchte). next() muss da also nicht zwingend nach exec() ausgeführt werden..