Schreibzugriff auf Datenbank mittels OLEDB



  • So, ich muss den Thread noch mal aufgreifen, da der unten stehende Link warum auch immer nicht funktioniert. Also nochmal kurz als Zusammenfassung:
    Ich habe folgendes Beispiel als grundlage genommen:
    http://www.codeproject.com/KB/database/oledbconsumer2.aspx

    Dort wird schreibend wie auch lesend auf eine Access-Datei zugegriffen, was auch funktioniert. Jetzt habe ich die Inhalte der Datei in einen MS SQL Server 2005 Express transferiert und habe die Accessor-Klasse wie folgt umgeschrieben:

    // Books.H : Declaration of the CBooks class
    
    #ifndef __BOOKS_H_
    #define __BOOKS_H_
    
    class CBooksAccessor
    {
    public:
    	TCHAR m_AuthorFirstName[51];
    	TCHAR m_AuthorLastName[51];
    	TCHAR m_Category[51];
    	LONG m_ID;
    	TCHAR m_price[51];
    	TCHAR m_Title[51];
    
    BEGIN_ACCESSOR_MAP(CBooksAccessor, 3)
    	BEGIN_ACCESSOR(0, true) /// accessor is the default auto accessor
    		COLUMN_ENTRY(1, m_ID)
    		COLUMN_ENTRY(2, m_Title)
    		COLUMN_ENTRY(3, m_AuthorFirstName)
    		COLUMN_ENTRY(4, m_AuthorLastName)
    		COLUMN_ENTRY(5, m_Category)
    		COLUMN_ENTRY(6, m_price)
    	END_ACCESSOR()
    	BEGIN_ACCESSOR(1, false)
    		COLUMN_ENTRY(1, m_AuthorFirstName)
    		COLUMN_ENTRY(2, m_AuthorLastName)
    	END_ACCESSOR()
    	BEGIN_ACCESSOR(2, false)
    		COLUMN_ENTRY(1, m_Category)
    	END_ACCESSOR()
    END_ACCESSOR_MAP()
    
    	// You may wish to call this function if you are inserting a record and wish to
    	// initialize all the fields, if you are not going to explicitly set all of them.
    	void ClearRecord()
    	{
    		memset(this, 0, sizeof(*this));
    	}
    };
    
    class CBooks : public CTable<CAccessor<CBooksAccessor> >
    {
    public:
    	HRESULT Open()
    	{
    		HRESULT		hr;
    
    		hr = OpenDataSource();
    		if (FAILED(hr))
    			return hr;
    
    		return OpenRowset();
    	}
    	HRESULT OpenDataSource()
    	{
    		HRESULT		hr;
    		CDataSource db;
    		CDBPropSet	dbinit(DBPROPSET_DBINIT);
    
    		dbinit.AddProperty(DBPROP_AUTH_CACHE_AUTHINFO, true);
    		dbinit.AddProperty(DBPROP_AUTH_ENCRYPT_PASSWORD, false);
    		dbinit.AddProperty(DBPROP_AUTH_MASK_PASSWORD, false);
    		dbinit.AddProperty(DBPROP_AUTH_PASSWORD, OLESTR("blabla"));
    		dbinit.AddProperty(DBPROP_AUTH_USERID, OLESTR("sa"));
    		//dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR("testbooks.mdb"));
    		dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR("MYServer\\MYDB"));
    		dbinit.AddProperty(DBPROP_INIT_CATALOG, OLESTR("Test_OLEDB"));
    		dbinit.AddProperty(DBPROP_INIT_MODE, (long)19);
    		dbinit.AddProperty(DBPROP_INIT_PROMPT, (short)4);
    		dbinit.AddProperty(DBPROP_INIT_PROVIDERSTRING, OLESTR(""));
    		dbinit.AddProperty(DBPROP_INIT_LCID, (long)1033);
    		hr = db.Open(_T("SQLOLEDB.1"), &dbinit);
    		if (FAILED(hr))
    			return hr;
    
    		return m_session.Open(db);
    	}
    	HRESULT OpenRowset()
    	{
    		// Set properties for open
    		CDBPropSet	propset(DBPROPSET_ROWSET);
    		propset.AddProperty(DBPROP_IRowsetChange, true);
    		propset.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE);
    
    		return CTable<CAccessor<CBooksAccessor> >::Open(m_session, _T("Books"), &propset);
    	}
    	CSession	m_session;
    };
    
    #endif // __BOOKS_H_
    

    Leider kann ich da nur lesend zugreifen, da beim Versuch eines Insert, Delete oder Update hr den Wert DB_E_ERRORSOCCURRED zurückwirft.
    Martin hatte schon gefragt, ob ein Recordset geöffnet sei und ob ich mehr Code über die Zugriffsmethoden zeigen kann. Ich habe diese unverändert gelassen, da die Art und Weise des Zugriffs ja gleich ist und es den Zugriffsklassen ja gleich sein kann, ob die auf eine mdb-Datei oder eine SQL-Server-Instanz zugreifen. Aber hier die Zugriffsmethoden:

    void COLEDBConsumer2Dlg::Update() 
    {
    	// TODO: Add your control notification handler code here
    
    	if( m_bCommand == true )
    	{
    		CommandUpdate();
    		return;
    	}
    
    	UpdateData( TRUE );
    	SaveData();
    
        HRESULT hResult = m_Books.SetData();
    	if( FAILED( hResult ) )
    	{
    		AfxMessageBox( _T( "Unable to save the rowset" ) );
    	}
    
    }
    
    void COLEDBConsumer2Dlg::Delete() 
    {
    	// TODO: Add your control notification handler code here
    	if( m_bCommand == true )
    	{
    		CommandDelete();
    		return;
    	}
    
    	HRESULT hResult = m_Books.Delete();
    	if( FAILED( hResult ) )
    	{
    		AfxMessageBox( _T( "Unable to delete the record" ) );
    	}
    	else
    	{
    		hResult = m_Books.MoveNext();
    		if( hResult != S_OK )
    		{
    			m_Books.MoveFirst();
    		}
    
    		CopyData();
    	}
    }
    
    void COLEDBConsumer2Dlg::CopyData()
    {
    	char szBuffer[ 25 ];
    
    	if( m_bCommand == true )
    	{
    		CommandCopyData();
    		return;
    	}
    
    	m_strAuthorFirstName = m_Books.m_AuthorFirstName;
    	m_strAuthorLastName = m_Books.m_AuthorLastName;
    	m_strCategory = m_Books.m_Category;
    	m_strID = ltoa( m_Books.m_ID, szBuffer, 10 );
    	m_strPrice = m_Books.m_price;
    	m_strTitle = m_Books.m_Title;
    
    	UpdateData( FALSE );
    }
    
    /// Insert a new item into the database
    void COLEDBConsumer2Dlg::Insert()
    {
    	if( m_bCommand == true )
    	{
    		CommandInsert();
    		return;
    	}
    
    	UpdateData( TRUE );
    
    	/// Note that the id is an incremental count therefore,
    	/// if we try to insert with a value that already exists in the id
    	/// it will error
    	m_Books.MoveLast();
    	int nCount = m_Books.m_ID;
    	nCount++;
    	SaveData();
    
    	m_Books.m_ID = nCount;
    
    	HRESULT hResult = m_Books.Insert(); /// specify the insert accessor
    	if( FAILED( hResult ) )
    	{
    		AfxMessageBox( _T( "Error inserting the current record" ) );
    		return;
    	}
    
    	m_Books.GetData( 0 );
    	m_Books.MoveFirst();
    
    	CopyData();
    
    }
    


  • So ein Verhalten hatte ich immer, wenn in der Datenbanktabelle kein Primärschlüssel angegeben war...



  • isabeau schrieb:

    So ein Verhalten hatte ich immer, wenn in der Datenbanktabelle kein Primärschlüssel angegeben war...

    Ich hab es sowohl ohne (so war das Beispiel) als auch mit PK versucht. Bei beiden keine Chance. Das witzige dabei ist, das es ja bei der mdb-Datei geht.



  • So, ich hab noch mal ein wenig rumprobiert. Ich habs jetzt geschafft einen Datensatz zu löschen, allerdings funktioniert insert und update nicht. Hat da jemand eine Erklärung?



  • Jetzt hab ich noch rausgefunden, dass er beim Zugriff auf die Access-Datei ein DB_S_ERRORSOCCURRED wirft und die Transaktion doch stattfindet. Kann es sein das ich nicht doch was bei den Property-Einstellungen vergessen habe bzw. falsch angelegt habe?
    Was ist denn seitens der Schnittstelle prinzipiell anders beim Zugriff auf eine mdb-Datei oder einen SQL-Server?


  • Mod

    Ist m_ID eine automatisch erzeugte ID?
    Dann kann hier schon das Problem liegen, dass Du sie zuweist.



  • Hallo Martin,

    derzeit wird die ID im Quelltext incrementiert. Damit hat es zumindest bei der Access-Datei funktioniert. Sicher könnte es damit zu tun haben, dass es jetzt beim SQL-Server nicht geht (das Problemn hatten wir glaube ich schon mal in einem anderen Thread diskutiert). Woher weiß man denn, ob das DBMS dies alleine macht oder man sich selber drum kümmern muss?
    Ich werde leider erst am Montag dazu kommen, dies zu testen.


Anmelden zum Antworten