Wie erklär ich meinem Recordset, auf welche DB er zugreifen soll?
-
Hi Leute also ich habe lokal sowas gemacht:
CDatabase db; db.Open( _T("ACR"),FALSE,true,_T("ODBC;UID=anyusr;PWD=anyusr"),false); CRecordset Set(&db); Set.Open(CRecordset::dynaset | CRecordset::forwardOnly, strSQL_Tests, CRecordset::readOnly);
Das geht ganz toll! Wenn ich das jetzt aber über Membervariablen machen will geht das nicht mehr. Ich hab folgendes versucht:
m_db.Open( _T("ACR"),FALSE,true,_T("ODBC;UID=anyusr;PWD=anyusr"),false); m_db.ExecuteSQL(SQL_CREATE_TMP); // erzeugt TMP Tabelle m_db.ExecuteSQL(SQL_FILL_TMP); // füllt TMP Tabelle m_Set.Open(CRecordset::dynaset , SQL_CNT_IO_NIO_TEILE, CRecordset::readOnly);
So aber die TMP die ich in der DB erstelle kennt jetzt mein Set nicht! weil er vermutlich auf die standard DB "pdb" zugreift, und in der die TMP nicht drin ist. Kann mir einer sagen wie ich das weg bekomme?
Wollte schon im Header oder beim aufruf der FKT Set(&db); machen, aber alles ohne Erfolg! Kann mir einer sagen wie ich dem Set klar mach dass er ne andere DB nehmen soll als die Standard?
Vielen Dank schon im Voraus.
-
Du musst das im Konstruktor des View(?) machen.
m_Set(m_db) muss oberhalb der { noch rein. Entweder mit , oder mit : davor, je nachdem, ob da schon was steht oder nicht.
-
Hmm das sieht für mich auf den ersten Blick so aus, als ob das Recordset, wenn es geöffnet wird eine neue Transaktion aufmachst, und die ExecuteSQL-Methoden in eine andere Transaktion schreiben.
hast du es mal mitm_db.Open( _T("ACR"),FALSE,true,_T("ODBC;UID=anyusr;PWD=anyusr"),false); m_db.ExecuteSQL(SQL_CREATE_TMP); // erzeugt TMP Tabelle m_db.ExecuteSQL(SQL_FILL_TMP); // füllt TMP Tabelle m_db.CommitTrans(); m_Set.Open(CRecordset::dynaset , SQL_CNT_IO_NIO_TEILE, CRecordset::readOnly);
versucht?
mfg
tobi
-
Hi Tobi nein hatte ich bis Dato noch nciht probiert aber ein Versuch meldet folgendes:
// BeginTrans must be called first #ifdef _DEBUG ASSERT(m_bTransactionPending); #endif
sprich ich hab keine Transaction offen. Aber Danke für den Tip!
EDIT: @Estartu: Ich will die FKT im Set aufrufen, drum wieso im Konstruktor der View?
-
Naja, stimmt schon, damit hättest du dann ja quasi ne verschachtelte Transaktion wenn du sie selber aufmachen muss, das bringt uns ja nicht weiter..
Du hast jetzt also dem RecordSet (m_Set) im Konstruktor den Pointer auf die Database-Instanz (m_db) gegeben und er bemerkt nicht das du m_db neu öffnest?
Oder hat das m_Set noch den Pointer auf dem standard (pdb) ? Das kannste ja überprüfen indem du die Variable m_Set.m_pDatabase vergleichst. Wenn das nicht stimmt, halt einfach mal neu zuweisen, wenns geht
-
OK
Also was ich nu weiß er greift noch auf die standard pdb zu, denn in der ist ne TMP-Tabelle und die findet er nu nicht! Wie soll ich das denn neu zuweisen? Sorry kein PLan!
-
ich hätte jetzt gesagt:
m_Set.m_pDatabase = &m_db;
funktioniert aber nicht, habe ich grad probiert
Scheinbar geht das nur im Konstruktor eine neue Datenbank-Verbindung ans RecordSet zu binden.
Muss das Recordset denn unbedingt eine Member-Var sein?Du musst erst CDatabase::Open() ausführen und danach CRecordSet::CRecordSet().
Aber du kannst natürlich nachträglich die Datenbankverbindung ändern, das funktioniert
Musst du nur vorher die alte verbindung schliessen, und deine Transaktion wird dabei auch abgeschlossen - also Rollback für SQL_CREATE_TMP und SQL_FILL_TMP is dann nicht mehr..
Also beim Konstruktoraufruf von m_Set auf jeden FallCRecordset m_Set(&m_db) // anstatt CRecordset m_Set(pdb)
-
Hm also ich hab
m_Set.m_pDatabase = &m_db;
auch grad nochmal probiert und bekomm dann immer einen ungültigen Cursor status
Aber die Idee ist glaub ich ganz richtig, wenn ich das in der MSDN richtig gelesen habe. Zu deiner Frage ob es denn unbedingt eine Member sein muss, folgendes.
Das Problem ist ich hab eine echt riesen DB über die ich eine Anzahl an IO Teilen und NIO Teilen ... suchen muss. Das klappt schon alles einwandfrei und steht dann auch in dieser TMP-Tabelle. So jetzt muss ich in ner View diese verschiedenen Werte anzeigen. Bisher hatte ich es einfach lokal gehalten (siehe erster Post) und dann ging es auch. Das sehr unschöne hierbei ist, dass ich ja hier die DB öffnen und am Ende der FKT wieder schließen muss. Sprich bei 8 Anfragen öffnet er 8 mal die DB 8 mal den Recset Erstellt 8 mal diese TMP füllt diese 8 mal ... Drum würde ich das gerne als Member halten. Dann kann ich nämlich open machen dann so oft ich will anfragen und dann wieder close. Es wäre aber schon schön wenn der Cursor und so weiter der anderen DB bestehen bleiben, da ich ja über ne bestimmte Auswahlmenge diese Details anzeigen will. Schließt der User also die Details soll er da weitermachen können wo er aufgehört hat. Wenn du ne Ahnung hast wie ich das ohne Member mache, dann benötige ich nicht unbedingt Members, aber mir ist leider keine Idee gekommen wie ich das machen könnte ohne Member.
Vielen Dank schon im Voraus
-
Andere Frage:
Warum kannst du die Werte nicht in einem Rutsch erzeugen und auslesen?Und eine Idee:
Mach die Database als Member aber das Recordset lokal.
Denn dein Problem ist ja, wie du dem Set die DB beibringst
und
wie die das Mehrfachöffnen der Datenbank verhinderst.Oder?
-
auf einen Rutsch erzeugen und auslesen geht. Frage ist nur wie übergebe ich das dann an meine View? ich kann doch nicht mehrere Werte aufs mal zurück geben, oder? Den Recset lokal lassen? glaub ich leider auch kaum dass das geht, denn der Recset übernimmt ja das Selecten, und wenn ich selecte schickt er die Anfrage wieder an die DB, oder? Sprich so oft wie ich selectiere (jedes mal das gleiche) so oft sendet er an die DB. Ich wäre um das öffnen drum rum gekommen, also ein kleiner Fortschritt. Aber ganz glücklich bin ich dann immernoch nicht. [EDIT] Und außerdem schaff ich es ja doch eben nicht den Set auf ne member DB zu verweisen.
// DOCH so schon! [/EDIT]
[EDIT]
So sieht es momentan aus:bool CACRSQLSet::OpenForCount(CString Bedingung) { m_db.Open( _T("ACR"),FALSE,true,_T("ODBC;UID=anyusr;PWD=anyusr"),false); m_db.ExecuteSQL(SQL_CREATE_TMP); // erzeugt TMP Tabelle m_db.ExecuteSQL(SQL_FILL_TMP); // füllt TMP Tabelle return true; } int CACRSQLSet::Count_nTeile(int io_nio_all) { CDBVariant nTeile; CDBVariant nErrCode; int sum = 0; CString Bedingung = " [ID] <= 500 "; m_Set.m_pDatabase = &m_db; m_Set.Open(CRecordset::dynaset , SQL_CNT_IO_NIO_TEILE, CRecordset::readOnly); switch (io_nio_all) { case 0: // IO m_Set.GetFieldValue("ANZAHL", nTeile, SQL_C_SLONG); m_Set.GetFieldValue("ErrCode", nErrCode, SQL_C_SLONG); if (nErrCode.m_lVal == 0) sum = nTeile.m_lVal; else sum = 0; break; case 1: // nio while(!m_Set.IsEOF()) { m_Set.GetFieldValue("ANZAHL", nTeile, SQL_C_SLONG); m_Set.GetFieldValue("ErrCode", nErrCode, SQL_C_SLONG); if (nErrCode.m_lVal == 0) m_Set.MoveNext(); else { sum += nTeile.m_lVal; m_Set.MoveNext(); } } break; case 2: // all while(!m_Set.IsEOF()) { m_Set.GetFieldValue("ANZAHL", nTeile,SQL_C_SLONG); sum += nTeile.m_lVal; m_Set.MoveNext(); } break; // default: } m_Set.Close(); return sum; }
-
Polofreak schrieb:
auf einen Rutsch erzeugen und auslesen geht. Frage ist nur wie übergebe ich das dann an meine View? ich kann doch nicht mehrere Werte aufs mal zurück geben, oder?
Wieso nicht? Schlimmstenfalls musst du die irgendwo zwischenspeichern.
(Bitte singende Bären vorstellen) Nichts ist unmöglich....Wenn ich das noch richtig im Kopf habe, willst du doch "nur" 3 Zahlen auslesen, richtig?
Dann würde ich die auch einfach in Members stopfen (nur wo wäre noch eine Frage...)long m_lIO; long m_lNIO; long m_lAlle;
Oder kannst du die vielleicht als Rückgabeparameter machen? Wär doch auch noch was.
-
das mit den members ist viel zu einfach dass ich drauf hätte kommen können
Wobei mir das mit den Rückgabeparametern besser gefällt, wie gebe ich denn mehrere Parameter an eine FKT zurück?
Es sind leider 3 Zahlen und ein CString. Aber sonst mach ich das wirklich mit members!
-
Polofreak schrieb:
das mit den members ist viel zu einfach dass ich drauf hätte kommen können
Jaja, das berühnte Brett vorm Kopf versperrt die Sicht. Soll ich die Kettensäge holen?
Polofreak schrieb:
Wobei mir das mit den Rückgabeparametern besser gefällt, wie gebe ich denn mehrere Parameter an eine FKT zurück?
Als Referenzen.
void Bla(int& nZahl)
Polofreak schrieb:
Es sind leider 3 Zahlen und ein CString. Aber sonst mach ich das wirklich mit members!
Wo ist das Problem?
Du kannst doch so viele Parameter machen, wie du brauchst.
-
estartu_de schrieb:
Jaja, das berühnte Brett vorm Kopf versperrt die Sicht. Soll ich die Kettensäge holen?
Ja wäre wohl besser!
estartu_de schrieb:
Wo ist das Problem?
Du kannst doch so viele Parameter machen, wie du brauchst.
ja öhm moment, ich wollte aus einer FKT das zurück geben!
Bitte nicht hauen ich weiß das sowas nicht geht! aber zum verständnis quasi sowas:int IO, int NIO, int all, CString Stats CountMotors(CString Bedingung);// Soll also ne FKT sein die mir die 4 Werte an die aufrufende FKT zurück gibt
Gibt es von der Idee her sowas? Wahrscheinlich nicht, wahrscheinlich werde ich dann in der FKT Members setzen und die Member dann über ne SetFKT an die andere Klasse übergeben.
Vielen Dank fürs Augen öffen (Brett zersägen)
-
*kettensägeschwing*
Ich hab dir doch gesagt wies geht.
Naja, wenn mans nicht kennt, isses wohl wirklich zu seltsam, also nochmal langsam:Wir haben eine kleine Beispielfunktion:
void Bla(int& nZahl) { nZahl = 5; }
Die muss man so aufrufen:
int nMeineZahl; // Man kann initialisieren, muss aber nicht. Bla(nMeineZahl); ASSERT(nMeineZahl == 5); // Der bleibt ruhig, weil ja grade 5 reingesteckt wurde.
Und so kannst du ja ohne Probleme auch mit verschiedenen Datentypen (und auch Klassen) und einer ziemlich beliebigen Anzahl verfahren.
Normalerweise schreibst du sicherlich:
void Bla(int nZahl)//...
In dem Fall wird der Speicher für einen int reserviert und der Inhalt der übergebenen Zahl (oben nMeineZahl) da rein kopiert.
Schreibt man aber int&, wird nicht der Inhalt sondern die Adresse übergeben. Das ist sowas wie ein Zeiger bzw. ein Alias.Jetzt besser? Sonst muss ich mal das Beispiel mit den Kisten ausgraben.
Kennst du vielleicht Turbo Pascal? Da schreibt man in dem Fall ein VAR vor den Parametertyp.Edit: Mir ist grade mein Merker eingefallen:
& heißt "Adresse von"
Mit dem kann man sich das in normale Sprache übersetzen:int n = 5;
n ist eine Zahl und wir stecken 5 rein.
int& nZahl;
nZahl ist eine Adresse von einem int
int* pZahl = &n;
pZahl ist ein Zeiger auf eine Zahl und weil wir da die Adresse von n reinstecken, zeigt der auf n.
TRACE("%d", *pZahl);
(Der Vollständigkeit halber)
Gib den Inhalt von pZahl aus. (Also 5)TRACE("%x", pZahl);
Gib pZahl aus. Das ist dann eine Speicheradresse.
Spiel sowas zur Not mal durch, wenn es dir unklar ist.
-
ne also für TurboPascal bin ích nu wirklich zu jung!
Ok ich hab jetzt verstanden wie du das meintest. Meine Funktion tut jetzt soooo gut!
Viele lieben Dank!
[edit]
so langsam versteh ich das mit den Pointern und gedöhns!
-
Polofreak schrieb:
ne also für TurboPascal bin ích nu wirklich zu jung!
Ey, mach mich nicht so alt.
TP ist ne Lernsprache und wird in Schulen gerne verwendet, weil die Lehrer nix anderes können - deswegen dachte ich...Polofreak schrieb:
Ok ich hab jetzt verstanden wie du das meintest. Meine Funktion tut jetzt soooo gut!
Viele lieben Dank!
Kein Problem.
Polofreak schrieb:
so langsam versteh ich das mit den Pointern und gedöhns!
Super.
Das ist auch blos Übungssache.
-
Hab in der Schule nie Proggen gelernt! Erst im Studium und da waren alle der Meinung TP braucht man nicht mehr.
Ja ein wenig üben sollte ich wohl noch mit dem ganzen Pointer gedöhns!
-
TP ist ne Lernsprache und wird in Schulen gerne verwendet, weil die Lehrer nix anderes können - deswegen dachte ich...
Stimmt - habe das inner 12. ööhhm, also 99/00 auch noch gelernt und soo alt bin ich nun auch noch nicht *ggg*
Das einfache "Pointergedöhns" ist eigentlich gar nicht so schlimm wenn mans erstmal gerafft hat. Man kann es sich dann aber auch kompliziert machen, dann wirds schwer
Im alten C-Stil einfache String-Verarbeitungen zu lesen ist mir immernoch ein graus, da macht doch ein std::string oder CString viel mehr Spasswhile(c && *c && *c != *(pLC->decimal_point)) *(p++) = *(c++); *p++ = *c++; s = c; while(c && *c) { if(c > s && !((c-s) % *(pLC->grouping))) *p++ = *(pLC->thousands_sep); *p++ = *c++; } *p = NULL;
sowas mein ich
-
Tow-B.de schrieb:
while(c && *c && *c != *(pLC->decimal_point)) *(p++) = *(c++); *p++ = *c++; s = c; while(c && *c) { if(c > s && !((c-s) % *(pLC->grouping))) *p++ = *(pLC->thousands_sep); *p++ = *c++; } *p = NULL;
sowas mein ich
Jaaaa, super!
Haste vielleicht noch Fifo und Lifo als Dreizeiler? Das fand ich sooo klasse, aber meine C-Mappe ist weg.
Das war mit ** und so.Wenn du 99/00 in der 12. warst, sind wir wohl gleichalt. Ich hab Oct99 nach der 11. meine Ausbildung angefangen.
Da war TP ein Hauptfach. Hach waren das Zeiten...