Qt4 Adatbázis kezelés

 ( kagy | 2008. október 16., csütörtök - 15:37 )

Üdv mindenkinek!

Qt4 adatbázis moduljával kapcsolatban lenne néhány kérdésem:

1, QSqlTableModel -ben az SQL hibákat, milyen módon tudom észrevenni és azokat lekezelni?

Kicsit bővebben: adva van az alábbi program részlet:

model = new QSqlTableModel(this);
model->setTable("CIM");
model->select();

ui.tvData->setModel(model);

a tvData QTableView típusú

Ez után szerkesztem a tvData-n keresztül a táblát (beszúrok új rekordot, törlök, módosítok, az ehhez kapcsolódó kód kész van)
A gond ott kezdődik hogyha pl egy új rekordot adok a táblához, de pl kulcs ütközés van arról nem kapok értesítést, de a tvData-ban látom mintha megtörtént volna a beszúrás, közben az adatbázis táblában nincs benne a rekord.
Hogyan lehet értesülni az adatbázis hibáról?

2, Hogyan tudom befolyásolni az oszlopok megjelenitési sorrendjét a QTableView osztályban ?
Kicsit bővebben: fenti kódrészletben a QTableView -ban a tábla oszlopok ugyan olyan sorrendben jellenek meg mint ahogy az adatbázisban táblában a mezők definiálva lettek, hogyan tudom más sorrendben megjeleníteni az oszlopokat.
pl.: Adatbázisban mezo1,mezo2,mezo3 ,mezo4-> megjeleníteni viszont így szeretném: mezo2,mezo4,mezo1,mező3

3. Hogyan tudom csak olvashatóvá tenni egy QsqlTableModel-t?
Szintén fenti kód részlet. Alap esetben QTableView keresztül tudom módosítani a tábla adatait ezt szeretném megtiltani, hogyan tehetem meg ?

4. QSqlTableModel, QSqlRelationalDelegate használva hogyan tudom szűkiteni a Delegate által felkínált lehetőségeket?
Konkrétabban:

model = new QSqlRelationalTableModel(this);
model->setTable("CIM");
model->setRelation(1, QSqlRelation("CIM_TIPUS", "KOD", "NEV"));
model->select();

ui.tvData->setModel(model);
ui.tvData->setItemDelegate(new QSqlRelationalDelegate(ui.tvData));

CIM táblábanak a TIPUS mezőjérre idegen kulcsként össze van rendelve a CIM_TIPUS tábla KÓD mezővel
A cél az lenne hogy amikor tvData-n keresztül szerkesztem a TIPUS mezőt akkor ne az CIM_TIPUS tábla összes elemét hozzá hanem csak egy részét (pl új címekhez valamilyen típust nem lehet felvinni). Valahogyan QSqlRelationalDelegate -be be kellene csempészni egy where feltételt. Ki hogyan oldja meg ezt a feladatott?

Előre is köszönöm a válaszokat!

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

1:
QSqlTableModel::lastError()

A QSqlTableModel::submit(), QSqlTableModel::submitAll() rendelkezik bool visszatérési értékkel. OnManualSubmit stratégiánál ezt könnyű ellenőrizni, egyébként nem tudom...
Lásd még: http://doc.trolltech.com/4.4/sql-cachedtable.html

2:
setQuery?
De lehet, hogy akkor nem lehet módosítani...

3:
QSqlQueryModel?
De talán a legegyszerűbb a View-en átállítani az QAbstractItemView::editTrigers-t

4:
Szerintem sehogy.
Vagy létrehozol egy szűkített táblát az adatbázisban, vagy implementálsz egy saját QItemDelegate-et...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Csak tipp: a 2 es 4 esetekben nem lehet megoldas egy VIEW a db-ben?
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

Köszi a válaszokat!

1, Amit javasolsz járhatónak tűnik, de ...!?

Leírom ide hogy jól értem -e azt amit javasoltál:
QSqlTableModel::EditStrategy -> QSqlTableModel::OnManualSubmit -ra
QSqlTableModel rowsInserted, és rowsRemoved signálokra rárakok egy slot-ot majd ebben commitelek és itt kezelem le az esetleges hibát. Ez rendben is van de rekord szerkesztéskor milyen signál generálódik ?

2, a QSqlTableModel setQuery fgv -je protected, így ehhez nem tudok hozzáférni.
(nem próbáltam, doksi alapján mondom) Esetleg más ötlet ?

3, Archívum kedvéért:
az előző példánál maradva:

ui.tvData->setEditTriggers(QAbstractItemView::NoEditTriggers);

4, Sajnos én is erre jutottam, úgy gondoltam ez annyira alap, probléma hogy biztos van rá valami kész osztály csak én nem találom, de ezek szerint hiába kerestem!

1.
QAbstractItemModel::dataChanged(...) biztos...
De nem tűnik logikusnak OnManualSubmit-ra váltani, aztán OnRowChange-t implementálni belőle.
A lastError elvileg mindig megmondja, hogy mi a hiba, azt is, ha nincs.
De most hirtelen én se találok semmilyen signal-t, amire ráakaszkodva adatbázis művelet után megnézhetnéd, hogy sikerült-e...
Talán a legegyszerűbb egy saját QSqlTableModel osztály, ahol az új submit()-ban meghívod a régit, és ellenörzöd, hogy sikerült-e.
Kérdezd meg a qt-interest-en.

2. Igazad van. Gyanítom, hogy nincs egyszerű megoldás.

3. Igen pont így. Máshol is olvastam, hogy így kell.

4. Ha nagyon kéne, talán bele tudnék magyarázni valamit, hogy ez miért nem SQL-es, de hagyjuk. :)
Feature request/qt-interest.

Egyébként az sql részt, és az egész Model/view framework-öt alig használtam párszor, így simán lehet, hogy én se tudok valamit. :)

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Sajnos ez a fgv protected és slot, ez szerintem nem oldja meg a problémámat.
Más ötlet ?

Csak egy apró megjegyzés, mert anno egy napot szívtam vele kb. másfél éve, lehet, h azóta javították: ha az oszlop neve tartalmazott olyan karaktereket, mint szóköz, ékezet, a Qt hibaüzenet nélkül elszáll. Csak ha esetleg belefutsz ilyesmibe.

--
The Net is indeed vast and infinite...
http://gablog.eu

Köszi a figyelmeztetést, egyelőre nem futottam bele mert soha nem használok ékezetes betűt és szóközt tábla és mező nevekben, jobb a békesség alapon ;)

Hello,

1. Szerintem is akkor jársz jól, és éred el a nagyobb rugalmasságot, ha a ManualSubmit irányt követed. Ez ugye a QTableView NoEditTriggerrel, és három gomb, vagy akármi az Insert, Update, Delete eseményekhez. Így el is felejtheted a rowsInserted és rowsDeleted signalokat, mert a saját, buttonclickekre lógatott slotInsert, slotUpdate, slotDelete slotokban hajtod végre a megfelelő műveleteket, értékeled ki az eredményt, kezeled le az esetleges lastError problémát, majd siker esetén frissíted a tábládat és a view-t.

2. Az alapértelmezett model/view osztályokkal sehogy. Vagy querymodelt használsz a tablemodel helyett, vagy - és trollék szerint is ez a keretrendszer legnagyobb erőssége - csinálsz egy saját származtatott modelt, ami lekezeli az oszlopok csereberélését. Ja, és használhatsz a modeleddel a view helyett egy tablewidgetet, amit kézzel töltögetsz :(

3. NoEditTrigger

4. Nincs jó megoldás az alapértelmezett model/view osztályokkal. Csinálj egy saját QSqlRelationalDelegatet, és írj neki saját setEditorData fgv-t.

Azért így az "1." elég fapados. Olyan FoxPro feeling. :)

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Fapad - miért lenne az?

a. Ha nem szereted az OnManualSubmitot , akkor marad a topic indítóban leírt mindenféle nyűg, vagy kénytelen vagy saját származtatott modelt és viewt használni. Ha ezt el akarod kerülni, az egyes pont a legsimább útja. Hogy buttonnal, shortcut key-val, vagy a viewn navigálással, az kb. mindegy.
Csinálhatsz insertnél updatenél formot pl. és máris megkerülted az sqlrelationaldelegate problémát is egy, a formon lévő szűrt adatsorral feltöltött comboval és widgetmapperrel.
Egy insert/update/delete kb. 10 sor kód hibakezeléssel.

b. Viszont kétségtelen, hogy a saját model és view sokkal elegánsabb és általánosabb megoldás :)

Volt már részem pár olyan melóban, ahol mindenképpen a "csak a viewn keresztül kezeljük az adattáblát" módszert kellett megvalósítani. Bitang sok munka van vele, (hibakezelések[magyarul], speciális delegatek, nem a default key-binding a viewn, stb.) és a b. pont a jó irány.
Viszont ha csak nagy hirtelen kell egy működő megoldás akkor jó az az a.
Ha jól emlékszem, van valahol egy form alapú példaprogram is a qt doksiban.

(1) Na most lehet hogy nem teljesen látom világosan, de ha insertRow(s) vagy insertRecord-dal teszed meg ezt akkor:

if (!model->insertRow(...)) //hiba van, lásd model->lastError()

Ha jól tévedek :) persze egy kicsit többet jó lenne látni hogy mi is történik a kódban.