在一个行集合上使用多个访问器

在三种基本方案中需要使用多个访问器:

  • 多个读/写行集。 在此方案中,你有一个具有主键的表。 你希望能够读取行中的所有列,包括主键。 你还希望能够将数据写入除主键以外的所有列(因为无法写入主键列)。 在此情况下,设置两个访问器:

    • 访问器 0 包含所有列。

    • 访问器 1 包含除主键以外的所有列。

  • 性能。 在此方案中,一个或多个列具有大量数据,例如图形、声音或视频文件。 每次移动到行时,你可能都不想检索具有大型数据文件的列,因为这样做会减慢应用程序的性能。

    可以设置单独的访问器,其中第一个访问器包含除具有大型数据的列以外的所有列,会自动从这些列中检索数据;第一个访问器是自动访问器。 第二个访问器只检索包含大型数据的列,但它不会自动从此列中检索数据。 可以让其他方法按需更新或提取大型数据。

    • 访问器 0 是自动访问器;它检索除具有大型数据的列以外的所有列。

    • 访问器 1 不是自动访问器;它检索除具有大型数据的列。

    使用自动参数指定访问器是否为自动访问器。

  • 多个 ISequentialStream 列。 在此方案中,你具有多个包含 ISequentialStream 数据的列。 但是,每个访问器都限制到一个 ISequentialStream 数据流。 若要解决此问题,请设置多个访问器,每个访问器都有一个 ISequentialStream 指针。

通常使用 BEGIN_ACCESSOREND_ACCESSOR 宏创建访问器。 也可以使用 db_accessor 属性。 (访问器在用户记录中进行了进一步介绍。)宏或属性指定访问器是自动访问器还是非自动访问器:

  • 在自动访问器中,移动方法(例如 MoveFirstMoveLastMoveNextMovePrev)会自动检索所有指定列的数据。 访问器 0 应该是自动访问器。

  • 在非自动访问器中,显式调用方法(如 UpdateInsertFetchDelete)之前不会进行检索。 在上述方案中,你可能不希望在每次移动中都检索所有列。 可以将一个或多个列放置在单独的访问器中,并使该访问器成为非自动访问器,如下所示。

以下示例使用多个访问器读取和写入SQL Server pubs 数据库的作业表。 此示例是多个访问器的最常见用法;请参阅上面的“多个读/写行集”方案。

用户记录类如下所示。 它设置两个访问器:访问器 0 仅包含主键列 (ID),访问器 1 包含其他列。

class CJobs
{
public:
    enum {
        sizeOfDescription = 51
    };

    short nID;
    char szDescription[ sizeOfDescription ];
    short nMinLvl;
    short nMaxLvl;

    DWORD dwID;
    DWORD dwDescription;
    DWORD dwMinLvl;
    DWORD dwMaxLvl;

BEGIN_ACCESSOR_MAP(CJobs, 2)
    // Accessor 0 is the automatic accessor
    BEGIN_ACCESSOR(0, true)
        COLUMN_ENTRY_STATUS(1, nID, dwID)
    END_ACCESSOR()
    // Accessor 1 is the non-automatic accessor
    BEGIN_ACCESSOR(1, true)
        COLUMN_ENTRY_STATUS(2, szDescription, dwDescription)
        COLUMN_ENTRY_STATUS(3, nMinLvl, dwMinLvl)
        COLUMN_ENTRY_STATUS(4, nMaxLvl, dwMaxLvl)
    END_ACCESSOR()
END_ACCESSOR_MAP()
};

主代码如下所示。 调用 MoveNext 会使用访问器 0 自动从主键列 ID 中检索数据。 请注意末尾附近的 Insert 方法如何使用访问器 1 来避免写入主键列。

int main(int argc, char* argv[])
{
    // Initialize COM
    ::CoInitialize(NULL);

    // Create instances of the data source and session
    CDataSource source;
    CSession session;
    HRESULT hr = S_OK;

    // Set initialization properties
    CDBPropSet dbinit(DBPROPSET_DBINIT);
    dbinit.AddProperty(DBPROP_AUTH_USERID, OLESTR("my_user_id"));
    dbinit.AddProperty(DBPROP_INIT_CATALOG, OLESTR("pubs"));
    dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR("(local)"));

    hr = source.Open("SQLOLEDB.1", &dbinit);
    if (hr == S_OK)
    {
        hr = session.Open(source);
        if (hr == S_OK)
        {
            // Ready to fetch/access data
            CTable<CAccessor<CJobs>> jobs;

            // Set properties for making the rowset a read/write cursor
            CDBPropSet dbRowset(DBPROPSET_ROWSET);
            dbRowset.AddProperty(DBPROP_CANFETCHBACKWARDS, true);
            dbRowset.AddProperty(DBPROP_CANSCROLLBACKWARDS, true);
            dbRowset.AddProperty(DBPROP_IRowsetChange, true);
            dbRowset.AddProperty(DBPROP_UPDATABILITY,
                DBPROPVAL_UP_INSERT | DBPROPVAL_UP_CHANGE |
                DBPROPVAL_UP_DELETE);

            hr = jobs.Open(session, "jobs", &dbRowset);
            if (hr == S_OK)
            {
                // Calling MoveNext automatically retrieves ID
                // (using accessor 0)
                while(jobs.MoveNext() == S_OK)
                   printf_s("Description = %s\n", jobs.szDescription);

                hr = jobs.MoveFirst();
                if (hr == S_OK)
                {
                    jobs.nID = 25;
                    strcpy_s(&jobs.szDescription[0],
                             jobs.sizeOfDescription,
                             "Developer");
                    jobs.nMinLvl = 10;
                    jobs.nMaxLvl = 20;

                    jobs.dwDescription = DBSTATUS_S_OK;
                    jobs.dwID = DBSTATUS_S_OK;
                    jobs.dwMaxLvl = DBSTATUS_S_OK;
                    jobs.dwMinLvl = DBSTATUS_S_OK;

                    // Insert method uses accessor 1
                    // (to avoid writing to the primary key column)
                    hr = jobs.Insert(1);
                }
                jobs.Close();
            }
            session.Close();
        }
        source.Close();
    }

    // Uninitialize COM
    ::CoUninitialize();
    return 0;
}

另请参阅

使用访问器
用户记录