Wie macht man den Schreibschutz an einem CRecordset weg?
-
Danke für die lange Erklärung.

Dass das alles noch nicht so super ist weiß ich.

Leider hatte ich bis vor kurzem Null Ahnung von Datenbanken und CRecordsets und hab mich dann wohl oder über mit dem einzigen Tutorial zu dem Thema befasst, dass ich gefunden habe (empfohlen bekam). Das Buch VC++ in 21 Tagen. Das hört aber auf, sobald man die grundlegenden Aktionen hinbekommt. (Bitte beachte, dass ich nicht geschrieben habe: "machen kann". Denn von Können kann wie du gesehen hast ja keine Rede sein.
) Das Buch für Fortgeschrittene ist in Arbeit, aber wohl noch lange nicht fertig.Exceptions mag ich außerdem nicht so gerne, da ich bei denen nie feststellen kann, wo das aus der Spur gelaufen ist. Sie mögen ja praktisch und viel verwendet sein, aber ich kann mich mit ihnen noch nicht anfreunden und vermeide sie bestmöglich.
Gibt es irgendwo was, wo ich mir ein vernüntiges Fehlerbehandlungskonzept angucken kann? Oder Richtlinien zur Erstellung? Ein gutes Buch?
Danke!

-
estartu_de schrieb:
Dass das alles noch nicht so super ist weiß ich.
ich gebe ja auch nur Tipps ab, wenn mir etwas besonders auffällt. Daß man damit manchmal jemanden auch hier im Forum "überfahren" kann (entweder mit der Fülle der Informationen oder auch nur durch Verwendung von "Konstrukten"/Konzepten, die man als Hobby-Programmierer natürlich nicht so schnell beherrschen muß), ist mir klar, denn nicht jeder macht das beruflich wie ich, aber dann kann man ja nachfragen. Bei dir weiß ich, daß es richtig ankommt, denn du bist in der gleichen Branche auch tätig

Daß da nicht alles am Anfang super ist, ist also ok und normal. Wenn ich da an mein erstes Programm im Praktikum in einer Firma denke, dann war das eigentlich auch ein unausgereifter Code, und hatte mit dem gleichen Gebiet zu tun, auf dem du dich mit deinem Code bewegst. Ich hatte gerade einen Windows-Entwickler-Kurs hinter mir, und sollte dann eine DB-Anwendung als Einstieg programmieren. Aber im Kurs hatten wir die MFC-Datenbank-Klassen nicht behandelt, du kannst dir vielleicht vorstellen, wie unbehaglich das für mich war. Da war ich froh, daß es Assistenten gibt, die einem die ganze Arbeit scheinbar abnehmen.
estartu_de schrieb:
Das hört aber auf, sobald man die grundlegenden Aktionen hinbekommt.
genau deswegen ist es wichtig, daß du auch mehrere Bücher gelesen und verstanden hast (oder wenn du es schon gelesen hast, dann noch einmal auffrischen), die nichts mit irgendeinem "Visual" usw. zu tun haben, "pure" C++ - Bücher, die am besten die Programmierung nur unter der Kommando-Zeile beschreiben (kann man ja trotzdem mit Visual C++ kompilieren). Dort wird natürlicherweise mehr auf die für die Sprache wichtigen Konzepte eingegangen.
estartu_de schrieb:
Denn von Können kann wie du gesehen hast ja keine Rede sein.
Können kommt in erster Linie von Erfahrung, auch ich dachte, als ich mein erstes C++ -Buch gelesen hatte, ich "kann" die Sprache. Ja, theoretisch konnte ich fast alles beantworten, aber das praktische Können war eher mäßig. Und das Können im Bereich Visual C++ ist wieder ein ganz anderes, aber wenn man ein reines C++ - Buch gelesen hat, und auch "reines C++" programmiert hat (oder auch mehrere, warum nicht), "kann" man wenigstens die Konzepte, und weiß, daß wenn eine Funktion Exceptions werfen kann, man diese auch behandeln sollte.
estartu_de schrieb:
Das Buch für Fortgeschrittene ist in Arbeit, aber wohl noch lange nicht fertig.
ich hoffe, es handelt sich um ein solches mit den oben angesprochenen Eigenschaften

estartu_de schrieb:
Exceptions mag ich außerdem nicht so gerne, da ich bei denen nie feststellen kann, wo das aus der Spur gelaufen ist. Sie mögen ja praktisch und viel verwendet sein, aber ich kann mich mit ihnen noch nicht anfreunden und vermeide sie bestmöglich.
du solltest auch bei diesem Thema nicht "von Null auf Hundert" starten. Das ist alles eine Sache des Konzepts, und du solltest dich schnellstmöglich mit Exceptions auseinandersetzen, und vermeiden solltest du sie auch nicht, sie tragen wesentlich dazu bei, daß die Fehlerbehandlung übersichtlicher wird. Das heißt aber noch lange nicht, daß jeder Code Exceptions werfen soll, auch hier ist eine Abwägung der Mittel nötig.
estartu_de schrieb:
Gibt es irgendwo was, wo ich mir ein vernüntiges Fehlerbehandlungskonzept angucken kann? Oder Richtlinien zur Erstellung? Ein gutes Buch?
also speziell ein Buch, das darauf (besonders) eingeht, kann ich dir nicht nennen, meine Erfahrung/Können im "Exception-Handling" ist auch mehr in der Praxis entstanden (selber programmiert, Code von anderen gelesen/übernommen), als aus Büchern. Aber zu diesem Thema solltest du dir auch mal die Buch-Tipps hier ansehen. Auch eine Frage zu diesem Thema im C++ - Forum (vielleicht nicht allgemein über Bücher, das wird da sicher öfter gefragt, sondern speziell zum Thema Fehler/Exception-Handling) wäre da nicht verkehrt.
Ich habe eigentlich erschreckend wenige Bücher (Stroustrup, Breymann) gelesen, bin aber dennoch, denke und hoffe ich, ein passabler Entwickler geworden, aber deswegen rate ich keinem, warte nur, das kommt alles mit praktischer Erfahrung, nur mein Weg ist eher so verlaufen.
ich hoffe trotzdem, du kommst dem "Fehlerteufel" auch jetzt schon auf die Schliche...
MfG
-
Wow, vielen Dank für deine Mühe.
Das Buch was ich meinte wird von Unix-Tom geschrieben. Ist zwar zu Mysql, aber immerhin mal was. http://www.c-plusplus.net/forum/viewtopic.php?t=56623
Ich habe hier so etwa 10 Bücher zum Programmieren mit VC++ aber in keinem werden Datenbanken behandelt.

Gut, zu Exceptions sollte ich mich dann mal ins C++ Forum wagen.
Aber was mich wundert: Ich möchte eine MFC Klasse nutzen und du rätst mir, mich mehr mit C++ zu befassen.

Das verstehe ich nicht so ganz. Ohne MFC fehlt doch CRecordset...Okay ich bin gleich von C (3 Semester in der Ausbildung) zu VC++6 gesprungen. C++ bestand aus einem Heft aus nem Zeitungsladen. Der Rest wurde gemischt gelernt und ohne klare Grenzen. Ein Kursus kam viel zu spät, denn der behandelte, was ich mir vorher beigebracht hatte. Ich hab halt immer im Projekt gelernt, aber jetzt sind keine Kollegen da zum Abgucken und Nachmachen.
Und der Datenbankteil ist leider neu für mich, denn den kenne ich nur als Firmenlösung (die dafür aber ziemlich gut, nur leider kann ich sie nicht nachbauen und darf auch nicht).Hast du vielleicht mal so einen Codeschnipsel zum Angucken? Ein Beispiel analysieren kann ich besser als die Informationen von Grund auf zusammensuchen.
Okay, ich mach jetzt einen "Kopfsprung" in das C++ Forum und werde da eine Runde lesen und ich werde zu Hause auch noch mal gucken ob ich noch was an Büchern übersehen habe.
Danke

-
void CFilialenSet::AddNew() { m_AdressSet.Open(); // Test ?!? m_AdressSet.AddNew(); CRecordset::AddNew(); }
-
also ich habe deine Formulierung "grundlegenden Aktionen" jetzt nicht als MFC-Grundlagen aufgefaßt, sondern eher allgemeiner, da du im Folgenden das Nicht-Vertrautsein mit Exceptions angeführt hast. Da bin ich evtl. über das Ziel hinausgeschossen, MFC-Programmierung und "reines C++" sind natürlich deutlich voneinander abgrenzbar. Und ich habe es jetzt noch einmal nachgelesen, es ging ja darum, daß du zum Ausdruck bringen wolltest, daß "VC++ in 21 Tagen" dort aufhört, wenn man eigentlich noch mehr Infos benötigen würde, also insofern kannst du meinen Bezug darauf vergessen, ich kann dir nur sagen, daß ich nur ein einziges Buch zu Visual C++ gelesen und durchgearbeitet habe, nämlich "Inside Visual C++", alles andere habe ich mir selbst erarbeitet (wurde dann auch gleich ins kalte Wasser geschmissen, und habe versucht, ohne weiteres Buch auszukommen, es hat geklappt...)
Aber es ging ja auch darum, daß CRecordset bei manchen Methoden eben Exceptions wirft, und es nützlich sein kann, dann die Info zu haben, wie man damit umgeht (im Grunde ist es ja nur ein try/catch). Und dies wird eben in MFC-Büchern nicht unbedingt so klar behandelt, weil man meist mit den vorgegebenen Klassen arbeitet. Auch ging es mir darum, anzudeuten, daß du das gleiche vielleicht etwas anders programmieren kannst, und da sind dann Stichworte wie Aggregation/Komposition usw...angebracht, aber die wirst du in keinem MFC-Buch finden, sondern eher in Büchern über Konzepte und sogenannte "design pattern". Dazu wäre es evtl. nötig, auf Assistenten-Code und -Klassen zu verzichten (du könntest z.B. eine eigene Klasse haben, die die Felder beider CRecordsets als Member hat, und von CRecordset abgeleitet ist usw...) Aber das nur als Erklärung, warum ich auf die "anderen Bücher" verwiesen habe, du solltest jetzt nicht gleich dein Programm so umwerfen, vielleicht ist der Fehler ja ganz einfach auch so zu beheben.
Einen Code, der auf dein Problem passen würde, und mit dem du jetzt konkret für diese Situation etwas anfangen kannst, habe ich leider nicht, denn, wie gesagt, ich verwende hier spezielle RecordSet-Klassen, die Felder werden in den Dokument-Klassen gehalten, DB-Zugriffe werden über die Recordset-Klasse abgewickelt (da hat sich jemand die Mühe gemacht, eine RecordSet-Klasse von CRecordSet abzuleiten, den Operator [] zu überschreiben, so daß ich auf Felder einfach mit rs["Feldname"] zugreifen kann usw...). Und ich kann dir nicht einmal den Code meiner DB-Anwendung für das Praktikum geben, weil ich genialerweise mir den Code nicht gesichert habe (die Anwendung war auch nur als Test gedacht, ob ich in der Lage bin, mich schnell in DB-Themen einzuarbeiten. Ich dachte, danach fragt sowieso keiner mehr, und so gut und schön war das auch nicht programmiert, dennoch würde ich davon natürlich etwas zeigen, wenn ich könnte. Aber ob es auf dein Problem gepaßt hätte, eher nicht, denn da wurden einfach mehrere CRecordView-Klassen verwendet, und keine Kombination, und Exception-Handling war auch nicht enthalten, naja, mein erstes größeres MFC-Programm eben).

Wahrscheinlich hast du hier auch nicht unbedingt grundsätzlich etwas falsch gemacht, es hakt vielleicht nur an einer Kleinigkeit.
MfG
-
@isabeau: Ich hab da nur ein ASSERT eingebaut (auf deinen Vorschlag hin) und jetzt geht es?

void CFilialenSet::AddNew() { ASSERT(m_AdressSet.IsOpen()); m_AdressSet.AddNew(); CRecordset::AddNew(); }Dafür kriege ich jetzt weiter hinten Probleme.

Aber da kann ich noch nichtmal genau sagen was er hat.Ich mache ein CancelUpdate weil nicht alle Eingaben okay waren. Und da drin meckert er an meinen Öffnungszeiten (alle NULL) herum.
Das mache ich wie oben auch schon. (Okay, Prüfung sollte man noch einbauen, aber ich bin mir SUPERSICHER, dass es okay ist - laut Debugger.)
void CFilialenSet::CancelUpdate() { m_AdressSet.CancelUpdate(); CRecordset::CancelUpdate(); }Und da erschießt er sich etwa:
void CRecordset::LoadFields() { ASSERT_VALID(this); ASSERT(m_nFieldsBound != 0); // Must clear out the old status ClearFieldStatus(); CFieldExchange fx(CFieldExchange::LoadField, this); DoFieldExchange(&fx); <------------------------ }Hier landet er genau:
_AFX_INLINE int CTime::GetYear() const { return (GetLocalTm(NULL)->tm_year) + 1900; } <--------Wieso landet der da in was passt ihn nicht?
Ich hab das doch extra NULL gesetzt, damit es LEER ist. Dann muss der doch nicht nach dem Jahr gucken.
Einen höher in der Aufrufliste finde ich das hier:void AFXAPI RFX_Date(CFieldExchange* pFX, LPCTSTR szName, CTime& value) { ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange))); ASSERT(AfxIsValidString(szName)); RETCODE nRetCode; UINT nField; if (!pFX->IsFieldType(&nField)) return; LONG* plLength = pFX->m_prs->GetFieldLengthBuffer( nField - 1, pFX->m_nFieldType); switch (pFX->m_nOperation) { default: //... case CFieldExchange::BindParam: //... case CFieldExchange::RebindParam: //... case CFieldExchange::BindFieldToColumn: // ... case CFieldExchange::BindFieldForUpdate: // ... case CFieldExchange::Fixup: //... case CFieldExchange::NameValue: //... case CFieldExchange::SetFieldNull: //... case CFieldExchange::MarkForAddNew: //... case CFieldExchange::MarkForUpdate: // ... case CFieldExchange::LoadField: { // Get the field data CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1]; // Restore the status pFX->m_prs->SetFieldStatus(nField - 1, pInfo->m_bStatus); // If not NULL, restore the value, length and proxy if (!pFX->m_prs->IsFieldStatusNull(nField - 1)) { AfxCopyValueByRef(pInfo->m_pvDataCache, &value, plLength, pInfo->m_nDataType); // Restore proxy for correct WHERE CURRENT OF operations TIMESTAMP_STRUCT* pts = (TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1]; pts->year = (SWORD)value.GetYear(); //<----- pts->month = (UWORD)value.GetMonth(); pts->day = (UWORD)value.GetDay(); pts->hour = (UWORD)value.GetHour(); pts->minute = (UWORD)value.GetMinute(); pts->second = (UWORD)value.GetSecond(); pts->fraction = 0; } else *plLength = SQL_NULL_DATA; #ifdef _DEBUG // Buffer address must not change - ODBC's SQLBindCol depends upon this if (pInfo->m_pvBindAddress != pFX->m_prs->m_pvFieldProxy[nField-1]) { TRACE1("Error: CString buffer (column %u) address has changed!\n", nField); ASSERT(FALSE); } #endif // _DEBUG } return; case CFieldExchange::AllocCache: //... } }Was kann ich dagegen machen?
@Probe-Nutzer:
Ich werde mich trotzdem nochmal mit C++ Büchern beschäftigen, da ich mich bisher doch nur auf VC++ beschränkt habe und da wohl einige Grundlagen weggelassen bzw. als bekannt vorausgesetzt werden.
Die Einkaufsliste liegt schon zu Hause.
Jetzt weiß ich auch, warum zwei Ex-Kollegen von mir oft gestritten haben und trotzdem ein Super-Team waren. Einer konnte C++ supergut und der andere VC++. Was der eine nicht optimal konnte, konnte der andere.
Ich hab mich allerdings mehr an den VC++ Mann gehalten... man merkts jetzt.Die "Kaltwasser-Methode" ist super zum Lernen, so komme ich jedenfalls am besten klar, nur mir fehlt momentan ein "Bademeister" der mich wieder rauszieht, wenn es brenzlig wird. Im Forum melde ich mich nur, wenn ich schon mehrfach in der Sackgasse war.
Ich hätte eingentlich auch lieber über Vererbung gearbeitet (der Zettel mit der Zeichnung liegt hier noch irgendwo...) aber ich habe keine Ahnung wie ich ein Recodset vernünftig mit mehreren Tabellen verbinde.

Die drei Tabellen sind ja noch die Aufwärmübung, das werden noch mehr.
Naja, ich suche jetzt erstmal nach dem Problem von oben und werde noch ne Runde lesen wenn ich nicht weiterkomme.
Dankeschön

-
Wenn ich mich nicht irre bedeutet GetLocalTm(NULL), dass er einen internen Speicher für das Datum benutzt (und keinen vom Progger festgelegten). Naja, und wenn kein Datum vorhanden ist, klappt eben GetYear() auch nicht.
Kannst ja mal zu Testzwecken die Datumsfelder mit einem gültigen CTime-Datum füllen.
-
Es passiert immer noch.

In allen Zeiten stand GetCurrentTime(). Also sollte damit alles in Ordnung sein.Der Datentyp ist CTime (es wird nur eine Uhrzeit gespeichert) kann das Problem daher kommen? Es ist meine erste Uhrzeit, die ich in die Datenbank schreibe.
-
Ja, könnte daran liegen. CTime funktioniert nur zwischen 1970 und 2038. Ausserdem kann es natürlich Probleme geben, wenn du da nur eine Uhrzeit drinn hast und GetYear() aufrufst, bzw. CFieldExchange::LoadField ruft ja nun mal GetYear() auf.
-
Aber wie soll ich das denn sonst machen? Ich habe in der Datenbank den Zeittyp genommen und habe das Control auch auf Uhrzeit gestellt. Da ist mir das Jahr egal... (Und die aktuelle Zeit sollte dohc keine Probleme machen?)
Naja, ich habe gesehen, dass es der Datensatz mit kompletten Zeiten IRGENDWIE in die Datenbank geschafft hat.

Ich habe ALLE Zeiten auf COleDateTime umgestellt und werde Montag noch eine Runde forschen.