OLEDB - wie kann man einen neuen Datensatz anlegen?
-
Ich hoffe ich bin im richtigen Forum. Denke aber das mein Problem mehr was mit der MFC wie mit der eigentlichen Datenbank zu tun hat.
Ich greife per OLEDB (OLEDB-Provider für ODBC) af eine MYSQL-Datenbank zu. Das Aslesen der Datensätze und das navigieren darin funktioniert. Nur wie kann ich darin einen neuen Datensatz anlegen? Bei ODBC gabs da die Memberfunktion m_pSet->AddNew(), der Zeiger meiner OLEDB-Klasse kennt die aber nicht? Ich habs schon mit Insert() versucht, nur da bricht das Programm ab. Hat da jemand eine Idee?
-
Hab jetzt rausgefunden, dass Insert E_NOINTERFACE returniert. Kann es sein das ich keine Schreibrechte auf die DB habe?
-
Nein! Vermutlich hast Du einfach kein offenes Rowset. Was machst Du denn eigentlich?
Zeige uns mal etwas Code!Verwendest Du die ATL OLEDB Client Templates?
-
Da muss ich glaub ich nochmal etwas weiter ausholen. Ich habe im ODBC-Admin eine normale ODBC-Verbindung als System-DSN angelegt. Der Verbinungstest funktioniert auch. Dann hab ich einfach nur zum Test eine SDI-Anwendung mit Datenbankunterstütung erstellt. Direkt ODBC zu verwenden funktioniert nicht, da er dort die Tabellen komischerweise nicht findest bzw. schon beim Projektanlegen das VS 2003.net sich komplett schließt. Dazu hatte ich schon mal angefragt: hier und hier.
Also jetzt das ganze mit OLE DB. Die Klasse sieht wie folgt aus:/ MySQL_OLEDBSet.h: Schnittstelle der Klasse CMySQL_OLEDBSet // #pragma once // Code generiert auf Mittwoch, 23. Mai 2007, 08:39 [ // #error Sicherheitsproblem: Die Verbindungszeichenfolge enthält möglicherweise ein Kennwort // Die Verbindungszeichenfolge enthält möglicherweise einfache Textkennwörter und/oder // andere vertrauliche Informationen. Entfernen Sie #error, nachdem Sie die // Verbindungszeichenfolge überprüft haben. Sie können das Kennwort // in einem anderen Format speichern oder eine andere Benutzerauthentifizierung verwenden. db_source(L"Provider=MSDASQL.1;Persist Security Info=False;User ID=root;Data Source=testconnection;Mode=ReadWrite;Extended Properties=\"DATABASE=test;DSN=testconnection;OPTION=0;PORT=0;SERVER=localhost;UID=root\""), db_table(L"tabelle1") ] class CMySQL_OLEDBSet { public: [ db_column(1, status=m_dwIDStatus, length=m_dwIDLength) ] LONG m_ID; [ db_column(2, status=m_dwDatenStatus, length=m_dwDatenLength) ] TCHAR m_Daten[46]; // Folgende vom Assistenten generierte Datenmember enthalten Statuswerte // für die entsprechenden Felder. Sie können // diese Werte als Null-Werte, die von der Datenbank // zurückgegeben werden, oder für vom Compiler ausgegebene Fehlerinformationen verwenden. // Weitere Informationen finden Sie in der Visual C++-Dokumentation unter Datenmember. // Hinweis: Diese Felder müssen vor dem Einfügen von Daten initialisiert werden. DBSTATUS m_dwIDStatus; DBSTATUS m_dwDatenStatus; // Folgende vom Assistenten generierte Datenmember enthalten Längenwerte // für die entsprechenden Felder. // Hinweis: Für Spalten mit variablen Längen müssen diese // Felder vor dem Einfügen von Daten initialisiert werden. DBLENGTH m_dwIDLength; DBLENGTH m_dwDatenLength; void GetRowsetProperties(CDBPropSet* pPropSet) { pPropSet->AddProperty(DBPROP_CANFETCHBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); pPropSet->AddProperty(DBPROP_CANSCROLLBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); } };Die DB enthält eine Tabelle, die nur aus einer Indexspalte und einer Datenspalte besteht. Um einen neuen Datensatz anzulegen gehe ich wie folgt vor:
void CMySQL_OLEDBView::OnBnClickedNeu() { // TODO: Fügen Sie hier Ihren Kontrollbehandlungscode für die Benachrichtigung ein. m_pSet->MoveLast(); m_pSet->m_ID=m_pSet->m_ID+1; strcpy(m_pSet->m_Daten,"neu"); UpdateData(); HRESULT hr=m_pSet->Insert(); if ( hr != S_OK ) { AfxMessageBox("hat nicht funktioniert"); } m_pSet->UpdateAll(); }Beim Debuggen hat hr entweder den Wert E_NOINTERFACE oder E_FAIL. In der MSDN steht dazu:
Remarks
This method requires the optional interface IRowsetChange, which might not be supported on all providers; if this is the case, the method returns E_NOINTERFACE. You must also set DBPROP_IRowsetChange to VARIANT_TRUE before calling Open on the table or command containing the rowset.
Insert might fail if one or more columns is not writable. Modify your cursor map to correct this.
Wenn ich aber
void GetRowsetProperties(CDBPropSet* pPropSet) { pPropSet->AddProperty(DBPROP_CANFETCHBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); pPropSet->AddProperty(DBPROP_CANSCROLLBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); pPropSet->AddProperty(DBPROP_IRowsetChange, VARIANT_TRUE); }erweitere, dann kann er die Datenbank nicht öffen. Hab leider noch nicht so viel Erfahrung mit OLE DB, wollte aber die MYSQL C++ API vermeiden.
-
AndyDD schrieb:
// Hinweis: Diese Felder müssen vor dem Einfügen von Daten initialisiert werden.
-
MFK schrieb:
AndyDD schrieb:
// Hinweis: Diese Felder müssen vor dem Einfügen von Daten initialisiert werden.Ok, das hab ich nicht beachtet. Aber wie macht man das? Was bedeutet dieser Status? Die Angaben in der MSDN helfen mir da auch nicht so richtig weiter. Aber der Rückgabewert E_NOINTERFACE deutet meiner Meinung nach nicht auf irgendein Statusproblem hin.
Ich werde das Gefühl nicht los das irgendwas mit den RowsetProperties nicht stimmt....
-
DBSTATUS gibt an ob das Feld beim Insert verwendet werden soll, oder NULL enthält uws. Lies die entsprechende MSDN Doku dazu.
Allerdings wird weder Länge noch Status zum Binden benötigt.
Tipp: Vergiss Attributed ATL. Du hast nur Scherereien damit!
-
Martin Richter schrieb:
DBSTATUS gibt an ob das Feld beim Insert verwendet werden soll, oder NULL enthält uws. Lies die entsprechende MSDN Doku dazu.
Allerdings wird weder Länge noch Status zum Binden benötigt.
Tipp: Vergiss Attributed ATL. Du hast nur Scherereien damit!
Danke, das bestätigt meinen Verdacht. Ich weiß das ich das z.B. zum Änderen von Feldinhalten benötige, wenn sich z.B. die Stringlänge ändert.
Wenn ich Attributed ATL vergessen soll, was schlägst Du für eine Alternative vor?
-
Die normale ATL OLE DB Client Variante. So anders ist das auch nicht. Etwas mehr Schreibarbeit.
Aber da kannst Du wenigstens Debuggen und sehen was wo passiert...
-
Was ist da genau der Unterschied bzw. wie kann man das umsetzen? Wie gesagt ich habe leider keine Ahnung davon, bin aber nun gezwungen mich damit zu befassen. Aber ich hab jetzt mich doch noch mal tiefer in die MSDN eingelesen und folgendes ergänzt:
void GetRowsetProperties(CDBPropSet* pPropSet) { pPropSet->AddProperty(DBPROP_CANFETCHBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); pPropSet->AddProperty(DBPROP_CANSCROLLBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); pPropSet->AddProperty(DBPROP_IRowsetChange, true, DBPROPOPTIONS_OPTIONAL); pPropSet->AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE); }Und jetzt kann ich Datensätze einfügen. Nur noch eine Frage: muss ich den Index (der in der DB als Primärschlüssel fungiert) vorgeben oder wird der von der DB beim Anlegen des neuen Datensatzes erstellt? Die Spalteneigenschaft der ID-Spalte steht ja auf AUTO INCREMENT.
-
Was soll ich da erklären? Du musst halt die normalen CCommand<> CRowset<> und so weiter templates verwenden.
Autoinc-Schlüssel werden von jeder DB anders behandelt.
Normalerweise muss der AutoInc Schlüssel gar nicht übergeben werden/gebunden. Bei einem Insert, das ist ja der Sinn. So ist das jedenfalls bei MS-SQL.Ob die erzeugte ID zurückgeliefert werden kann liegt auch am Provider. MS-SQL benötigt dafür DBPROP_SERVERDATAONINSERT!