QSqlTableModel mit Sqlite blockiert DBTabelle!?

Alles rund um die Programmierung mit Qt
Antworten
Arocz
Beiträge: 18
Registriert: 3. Februar 2010 09:06
Wohnort: Edermünde Besse

QSqlTableModel mit Sqlite blockiert DBTabelle!?

Beitrag von Arocz »

Hallo Leute,

sitze nun seit ner Woche an nem blöden Problem, wir nutzen Qt 4.5.2.
Habe schon in eurem Forum gesucht, allerdings keine Lösung gefunden.

Habe eine Sql Datenbank(Sqlite) welche über ein SqlTableModel und ein TableView angezeigt wird.

Sql Tabelle wird mit 256 Datensätzen gefüttert(einfaches CREATE, INSERT)
danach wird ein DROP ausgführt. Funktioniert Tabelle ist weg.
Sql Tabelle wird mit 257 Datensätzen gefüttert(einfaches CREATE, INSERT)
danach wird ein DROP ausgführt. Bekomme eine Fehlermeldung :"database table is locked Unable to fetch row" .

Habe in der Doku rumgesucht, finde da allerdings keine Erklärung zu dem Problem.
Also hab ich ein kleines Programm erstellt und versucht das nachzustellen.
das Problem konnte ich dort mit der Lösung:

Code: Alles auswählen

 while (m_tableModel->canFetchMore()) m_tableModel->fetchMore();

beheben. Meine Tabelle wurde ordnungsgemäß gelöscht.

Allerdings lässt sich das nicht auf mein großes Projekt zurückführen. Queries laufen keine auf der Tabelle, denn DELETE oder andere SQL-Befehle lassen sich auch ausführen. nur der DROP schmeißt diese Fehlermeldung und auch nur wenn ich mehr als 257 Datensätze habe.

habt ihr schonmal sowas gehabt? welche Möglichkeiten gibt es das diese Tabelle nicht mehr blockiert wird!? In der Doku finde ich nichts, bin echt ratlos.

Danke für die Hilfe schonmal im Voraus.
Gruß
Arkadius
Arocz
Beiträge: 18
Registriert: 3. Februar 2010 09:06
Wohnort: Edermünde Besse

Beitrag von Arocz »

keine Ideeen? Oder fehlen euch Informationen?
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

ich würde sagen mangels Information auch keine Ideen... :wink:
Spannend wäre halt eine komplette Demo..

Auch der Ablauf ist nicht ganz klar.. wie genau gehst du denn vor? Verstehe ich das richtig:
1. CREATE... und INSERT...
2. Erstelle Model
3. DROP.. // Fehler bei mehr als 256 Datensätze
4. Model lebt noch

Kannst du evt. auch noch etwas mehr über deine Anwendung schreiben? Warum werden dynamisch Tabellen erstellt und gelöscht (lässt sich da am Datenbankdesign noch was ändern...)? Werden die Daten nach dem Drop noch irgendwo (in einem Model) benötigt? Wenn ja, warum?

Gruss..
Arocz
Beiträge: 18
Registriert: 3. Februar 2010 09:06
Wohnort: Edermünde Besse

Beitrag von Arocz »

ich würde sagen mangels Information auch keine Ideen...
hehe ...dann versuch ich mal den Informationsmangel zu beheben...hatte lediglich versucht mich kurz zu fassen... ist mir wohl misslungen :lol:
Kannst du evt. auch noch etwas mehr über deine Anwendung schreiben?
da es ein riesiges Projekt ist, versuche ich es ersteinmal ohne Code zuposten.

Im groben läuft das Programm foglendermaßen ab:

Programm startet, sqlite Datenbank wird erstellt, Projekt wird geladen(Zip-File welches entpackt wird, die innenliegenden Xml, csv und anderen dateien werden in einem normalen ordner gespeichert).
Aus einer dieser XML-Files wird eine Datenbanktabelle erstellt(wir benutzen die Datenbank nur um mit den datensätzen arbeiten zu können, da wir manchmal mehr als 10000 Einträge haben).
Also während die XML ausgelesen wird einmal ein CREATE gemacht und danach die folgen die INSERT statements. Projekt ist dann geladen.

Dann werden die Views aufgebaut.
In dem einem Fall sind es dann ein geerbtes QSqlTableModel und ein geerbtes QTableView(welches auch eigens implementierte Header hat).
Diese sitzen auf einem Widget welches Funktionen bereitstellt diese Tabelle zu manipulieren(Datensätze hinzufügen, ändern, löschen, Filter setzen, sortierung durchführen), außerdem ist es möglich Spalten hinzuzufügen, zu ändern oder zu löschen. Das alles läuft über OnManualSubmit.

Wenn der Benutzer nun seine geänderte Tabelle speichern will(submit ist erfolgt, der save button wird gedrückt), wird die datenbanktabelle zeile für zeile ausgelesen und in eine XML gespeichert(welche später in das zip-file kommt). somit kann er das programm schließen und beim nächsten mal wieder weiterarbeiten.

Soviel zum Ablauf.
Warum werden dynamisch Tabellen erstellt und gelöscht
Das besagte Problem tritt nun immer dann auf wenn der Benutzer seine mehr als 256 Datensätze hat, und die Spalten ändern möchte(einfachen Spaltennamen ändern, passiert leider viel zu oft aber der Nutzer braucht es). Eine solche Strukturänderung erzwinge ich, indem ich die neue Struktur in die XML schreibe, auf der Datenbank Tabelle einen DROP ausführe und die XML neulade(funktioniert wunderbar mit weniger als 256 Datensätzen).

Alle anderen queries funktionieren! INSERT DELETE usw

Wenn ich das Model komplett wegnehme(keine instanz oder kein setTable) funktioniert es auch mit mehr als 256 Datensätzen, habe allerdings dann keine Darstellung, diese brauche ich aber :( .

Wenn ich kurz vor dem DROP die Schleife mit canFetchMore und fetchMore durchlaufen lasse klappt es nicht,
auch die Methode dem Model die Tabelle kurz vorher wegzunehmen (setTable("")) funktioniert nicht(habe diese beiden Methoden probiert weil sie in einem kleinen Beispielprogramm funktionierten).

Ich vermute mal das es am Model liegt, weiß es aber leider nicht. Welches Objekt kann die Tabelle blockieren? und wie kann man dem sagen, dass es damit aufhören soll!? :?
(lässt sich da am Datenbankdesign noch was ändern...)?
eigentlich ist dahinter kein großes datenbank design, sind nur 4 tabellen welche halt vieeeele datensätze haben und diese sind im ersten moment nichtmal verknüpft, zumindest erfährt die datenbank nichts darüber.
Werden die Daten nach dem Drop noch irgendwo (in einem Model) benötigt? Wenn ja, warum?
Nein, die Daten sind zu dem Zeitpunkt in der XML gespeichert.

Ich hoffe auf gute Ideeen :wink: und danke schonmal!
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Temporäre Datenbank nur zur Anzeige hab ich noch nie gehört :D
Ich würde sagen du schreibst dir ein eigenes kleines Model OHNE Datenbank. Das sollte doch vollkommen reichen.

Ansonsten kann natürlich jedes noch exisiterende QSqlQuery und QSqlRecord deine DB blockieren.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Mir ist klar, dass du einfach nur das DB-Problem geloest haben moechtest, aber ich frage doch nochmal nach:

Du moechtest einfach nur eine XML-Datei
1. laden
2. bearbeiten
3. wieder als Datei speichern.

Was ich noch nicht verstanden habe: wozu den Umweg uber die Datenbank? Warum nicht einfach ein eigenes (XML-)Model, welches entsprechende Methoden hat?

Code: Alles auswählen

 MyXmlModel *model = new MyXmlModel();
 view->setModel(model);
 model->loadFile("/tmp/xyz.xml");
 ...

 ...
 ... // irgendwann spaeter nach dem Bearbeiten
  model->saveFile("/tmp/neu.xml");
Den XML-Parser hast du offensichtlich ja schon (du erstellt und befuellst momentan ja die Datenbank damit). Warum also nicht die DB komplett weglassen?
Arocz
Beiträge: 18
Registriert: 3. Februar 2010 09:06
Wohnort: Edermünde Besse

Beitrag von Arocz »

wozu den Umweg uber die Datenbank? Warum nicht einfach ein eigenes (XML-)Model, welches entsprechende Methoden hat?
Die Datenbank wird halt gebraucht, um zum einen die Datenmengen zu bewältigen und zum anderen weil der Anwender es so braucht.
Sie wird noch von anderen Bestandteilen der Anwendung benutzt, welche ohne einem Model arbeiten. zum Beispiel werden andere Tabellen oder Views erstellt welche Daten aus genau dieser Tabelle brauchen(CREATE AS SELECT ...) diese Erstellen zum beispiel CSVs mit zusammengefassten Daten. Im Zuge, dass ich den Fehler finden will habe ich diese Bestandteile natürlich temporär ausgeschaltet. Ich verstehe natürlich deine Zweifel :wink: für welchen Zweck die DB gebraucht wird, leider kann ich sie in diesem Schritt nicht weglassen.

Tatsache ist:
Wenn ich das Problem in einem eigenen kleinen Projekt nachstelle, lässt das Model den DROP mit mehr als 256 Datensätzen zu(mit den probierten Methoden).
Versuche ich diese Methode in meine Anwendung zurückzuführen, klappt es nicht.
Also bin ich davon ausgegangen das es noch andere Models gibt die diese Tabelle nutzen.
Habe also angefangen alle Models temporär auszuschalten(alle setTables raus), angefangen bei dem Model welches die Tabelle direkt zeigt. Dieses Model wird nicht instanziiert oder es wird initial kein setTable ausgeführt(beides probiert). Dann klappt der DROP. Der Versuch das setTable kurz vor dem DROP auf eine leere Tabelle zu setzen schlägt fehl.

Die Frage ist warum das Model dennoch dann die Tabelle blockiert? und wie man das beheben kann.

Ich sitze schon seit dem 25.01. an dieser Sache und bin echt verzweifelt :(
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Debugger oder qDebug-Ausgaben auf der Konsole überall davor/danach wo du Daten aus der DB holst/schreibst.
Ich hab auch oben schon geschrieben, dass offene QSqlQueries/Records die db blockieren können.

Es ist nicht gerade sicheres Design, eine DB über mehrere Models/Views zu verteilen und irgendwo dann ein DROP loslassen, wo andere Views noch Daten aus der DB anzeigen.
Du kannst dem Abhilfe verschaffen, indem du ein Signal loslässt "droppingTable( const QString & )", welches alle interessierten Parteien vor dem kommenden Unheil warnt, die dann alle Hände von der DB nehmen. in der nächsten Event-Runde solltest du dann sicher deinen DROP machen können.

Aber die eleganteste Sache wär natürlich ein eigenes XML-Model.
Arocz
Beiträge: 18
Registriert: 3. Februar 2010 09:06
Wohnort: Edermünde Besse

Beitrag von Arocz »

@franzf:
Ich hab auch oben schon geschrieben, dass offene QSqlQueries/Records die db blockieren können.
Stimme ich dir natürlich zu, aber wenn ich 256 datensätze(oder weniger) habe, kann ich den query ja ausführen. Was doch belegt das da sonst nichts drüber läuft oder irre ich mich da? Und alle anderen query lassen sich doch auch aufder tabelle ausführen. wenn ich mich irre dann bitte korrigiert mich.
Es ist nicht gerade sicheres Design, eine DB über mehrere Models/Views zu verteilen und irgendwo dann ein DROP loslassen, wo andere Views noch Daten aus der DB anzeigen.
Nunja ich hab mir das design selber nicht ausgedacht, löffel grad nur eine Suppe aus(wie man so schön sagt). Ich habe die Sache ja mittlerweile soweit beschränkt, das die Tabelle wirklich nur noch von dem einem Model genutzt wird. Es gibt zwar noch mehrere Tabellen in der DB aber das sollte doch kein Problem sein oder!? Erfährt das Modell nicht von der Tabelle wird der DROP durchgeführt. mach ich nen setTable("tabelle1") geht der query nicht mehr, zumindest wenn ich mehr als 256 datensätze habe. und ich hab schon viele möglichkeiten getestet... aber mehr als 256 datensätze...zack wird die tabelle geblockt :(
Arocz
Beiträge: 18
Registriert: 3. Februar 2010 09:06
Wohnort: Edermünde Besse

Beitrag von Arocz »

....gehe ich richtig mit der Annahme das noch keiner das Problem hatte!?
Antworten