[solved] querys in mehreren Klassen

Alles rund um die Programmierung mit Qt
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

[solved] querys in mehreren Klassen

Beitrag 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

Code: Alles auswählen

QSqlQuery qry(db);
qry.prepare("...");
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.

Code: Alles auswählen

QSqlQuery::value: not positioned on a valid record
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

Code: Alles auswählen

QSqlDatabase db = QSqlDatabase::database();
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
Zuletzt geändert von C167 am 3. April 2008 15:25, insgesamt 1-mal geändert.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Wie Du schon gesagt hast - einfach QSqlDatabase::database("name") benutzen und fertig.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

bisweilen wird das Programm auch per SegFault terminiert.
Hast du Multithreading?
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag 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
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag 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 !?
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag 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.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag 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.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Code: Alles auswählen

private:
      QSqlDatabase db; 
und

Code: Alles auswählen

MainPage::MainPage ( QSqlDatabase db, QWidget *parent )
      : QWidget ( parent )/*, db ( db )*/
{
   db = QSqlDatabase::database(); 
Macht nicht das, was du denkst...
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag 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:

Code: Alles auswählen

private:
      QSqlDatabase db; 
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}.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag 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..
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag von C167 »

Au verdammt, da hast du recht.
Ich hab jetzt mal

Code: Alles auswählen

this->db = QSqlDatabase::database();
gemacht, aber es geht trotzdem nicht
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Hau endlich deine Klassenvariable weg, nimm einen Namen und fertig!
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag 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()")?
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag 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

Code: Alles auswählen

db = db_conn;
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
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag 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..
Antworten