Programming with Microsoft Visual C++.NET 6ed [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Programming with Microsoft Visual C++.NET 6ed [Electronic resources] - نسخه متنی

George Shepherd, David Kruglinski

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
توضیحات
افزودن یادداشت جدید








Creating an OLE DB Consumer


Creating an OLE DB consumer is pretty straightforward—most of the support comes through the ATL OLE DB Consumer Wizard. You can see an example of a consumer in the Ex27 folder on the companion CD. Here are the steps for creating a consumer using the ATL OLE DB Consumer Wizard:



  1. Create an application or a control to drive the data consumption. For example, you might want to create an ActiveX control.



  2. While you're in Visual Studio .NET, use the ATL OLE DB Consumer Wizard (shown in Figure 27-1) to insert a data consumer. (Choose Add Class from the Project menu and then select ATL OLE DB Consumer from the class templates.)


    Figure 27-1: The ATL OLE DB Consumer Wizard.



  3. On the wizard's only page, name the class, select the data source, and specify a table or command object and the kinds of updates (change, insert, delete) to be supported in the consumer.



  4. Click the Data Source button to configure the data consumer. Once you've selected a data source, click OK. The wizard will create an OLE DB consumer template for you.



As an example, we took a Microsoft Access database named Biblio.mdb and made a data consumer out of it. The Biblio database includes the titles and the authors of various programming texts. Using the ATL OLE DB Consumer Wizard to create the OLE DB consumer template for the authors in the database yielded these classes:

// Authors.h : Declaration of the CAuthors
#pragma once
// code generated on Wednesday, April 17, 2002, 10:25 AM
class CAuthorsAccessor
{
public:
LONG m_Au_ID;
TCHAR m_Author[51];
SHORT m_YearBorn;
// The following wizard-generated data members contain status
// values for the corresponding fields in the column map. You
// can use these values to hold NULL values that the database
// returns or to hold error information when the compiler returns
// errors. See Field Status Data Members in Wizard-Generated
// Accessors in the Visual C++ documentation for more information
// on using these fields.
// NOTE: You must initialize these fields
// before setting/inserting data!
DBSTATUS m_dwAu_IDStatus;
DBSTATUS m_dwAuthorStatus;
DBSTATUS m_dwYearBornStatus;
// The following wizard-generated data members contain length
// values for the corresponding fields in the column map.
// NOTE: For variable-length columns, you must initialize these
// fields before setting/inserting data!
DBLENGTH m_dwAu_IDLength;
DBLENGTH m_dwAuthorLength;
DBLENGTH m_dwYearBornLength;
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);
}
HRESULT OpenDataSource()
{
CDataSource _db;
HRESULT hr;
// Here goes the _db.OpenFromInitializationString


if (FAILED(hr))
{
#ifdef _DEBUG
AtlTraceErrorRecords(hr);
#endif
return hr;
}
return m_session.Open(_db);
}
void CloseDataSource()
{
m_session.Close();
}
operator const CSession&()
{
return m_session;
}
CSession m_session;
DEFINE_COMMAND_EX(CAuthorsAccessor, L" SELECT Au_ID, Author, 'Year Born' FROM Authors")
BEGIN_COLUMN_MAP(CAuthorsAccessor)
COLUMN_ENTRY_LENGTH_STATUS(1, m_Au_ID,
m_dwAu_IDLength, m_dwAu_IDStatus)
COLUMN_ENTRY_LENGTH_STATUS(2,
m_Author, m_dwAuthorLength, m_dwAuthorStatus)
COLUMN_ENTRY_LENGTH_STATUS(3,
m_YearBorn, m_dwYearBornLength, m_dwYearBornStatus)
END_COLUMN_MAP()
};
class CAuthors : public CCommand<CAccessor<CAuthorsAccessor> >
{
public:
HRESULT OpenAll()
{
HRESULT hr;
hr = OpenDataSource();
if (FAILED(hr))
return hr;
__if_exists(GetRowsetProperties)
{
CDBPropSet propset(DBPROPSET_ROWSET);
__if_exists(HasBookmark)
{
propset.AddProperty(DBPROP_IRowsetLocate, true);
}
GetRowsetProperties(&propset);
return OpenRowset(&propset);
}
__if_not_exists(GetRowsetProperties)
{
__if_exists(HasBookmark)
{
CDBPropSet propset(DBPROPSET_ROWSET);
propset.AddProperty(DBPROP_IRowsetLocate, true);
return OpenRowset(&propset);
}
}
return OpenRowset();
}
HRESULT OpenRowset(DBPROPSET *pPropSet = NULL)
{
HRESULT hr = Open(m_session, L"Authors", pPropSet);
#ifdef _DEBUG
if(FAILED(hr))
AtlTraceErrorRecords(hr);
#endif
return hr;
}
void CloseAll()
{
Close();
ReleaseCommand();
CloseDataSource();
}
};


The CAuthorsAccessor class defines the structure of the author record. Notice that the class includes an author ID field, a name field, and a field indicating when the author was born.

The CAuthors class represents the actual data consumer class that connects to the database. Notice that it's derived from CCommand. Remember that command objects represent a command (such as a SQL statement) and generate rowsets. The COLUMN_MAP represents data returned in the rowset. The PARAM_MAP represents parameter data for a command.

The column maps and the parameter maps represent the user's view of the accessor. As with many data structures in ATL and MFC, these maps are built up with macros. Here's how the maps work: Data returned by a database is contained in a contiguous block of memory. OLE DB templates work with this block of memory to extract the data. The data members in the entries represent offsets into that block of memory. The entries in the maps filter out the data from the database. That way, the developer doesn't have to worry about doing anything funky like performing pointer arithmetic on the block to get information.


Using the OLE DB Consumer Code


Using the database consumer class is just about as easy as creating it. Here's how to take advantage of the database consumer class:



  1. Declare an instance of CAuthors wherever you need to use it:

    class CUseAuthors : public CDialog {
    CAuthors m_authors;


    };




  2. Open the Authors table by calling Open on the database consumer object:

    CUseAuthors::OnInitDialog() {
    m_authors.Open();
    }



  3. Use member functions to navigate through and manipulate the database. Here's a short sampling of some of the things you can do:

    CUseAuthors::OnNext() {
    m_authors.MoveNext();
    }
    CUseAuthors::OnFirst() {
    m_authors.MoveFirst();
    }
    CUseAuthors::OnLast() {
    m_authors.MoveLast();
    }
    CUseAuthors::OnInsert() {
    m_authors.Insert();
    }



  4. As you navigate through the database, the data will end up in the member variables. For example, to find out the name of the next author in the database, you use code that looks like this:

    m_authors.MoveNext();
    m_strAuthorName = m_authors.m_Author;



As you can see, using the templates greatly simplifies getting the data out of the database. All you need to do is find the database, point the ATL OLE DB Consumer Wizard to it, and get the wizard to generate your code. You can then use accessor class functions to move around the database and fetch the data. The other half of the OLE DB template equation is the data provider, which we'll discuss next.



/ 319