Erstellen eines aktualisierbaren Anbieters

Visual C++ unterstützt aktualisierbare Anbieter oder Anbieter, die den Datenspeicher aktualisieren (schreiben in) können. In diesem Thema wird erläutert, wie Aktualisierbare Anbieter mithilfe von OLE DB-Vorlagen erstellt werden.

In diesem Thema wird davon ausgegangen, dass Sie mit einem funktionsfähigen Anbieter beginnen. Es gibt zwei Schritte zum Erstellen eines aktualisierbaren Anbieters. Sie müssen zuerst entscheiden, wie der Anbieter Änderungen am Datenspeicher vornehmen wird; insbesondere, ob Änderungen sofort oder zurückgestellt werden sollen, bis ein Updatebefehl ausgegeben wird. Im Abschnitt "Erstellen von Anbietern aktualisierbar" werden die Änderungen und Einstellungen beschrieben, die Sie im Anbietercode ausführen müssen.

Als Nächstes müssen Sie sicherstellen, dass Ihr Anbieter alle Funktionen enthält, um alles zu unterstützen, was der Verbraucher möglicherweise anfordert. Wenn der Verbraucher den Datenspeicher aktualisieren möchte, muss der Anbieter Code enthalten, der Daten im Datenspeicher speichert. Sie können z. B. die C-Laufzeitbibliothek oder MFC verwenden, um solche Vorgänge für Ihre Datenquelle auszuführen. Im Abschnitt "Schreiben in die Datenquelle" wird beschrieben, wie Sie in die Datenquelle schreiben, mit NULL- und Standardwerten umgehen und Spaltenkennzeichnungen festlegen.

Hinweis

UpdatePV ist ein Beispiel für einen aktualisierbaren Anbieter. UpdatePV ist identisch mit MyProv, aber mit aktualisierbarer Unterstützung.

Anbieter aktualisierbar machen

Der Schlüssel, einen Anbieter aktualisierbar zu machen, besteht darin, zu verstehen, welche Vorgänge Ihr Anbieter für den Datenspeicher ausführen soll und wie der Anbieter diese Vorgänge ausführen soll. Insbesondere besteht das Hauptproblem darin, ob Aktualisierungen des Datenspeichers sofort oder verzögert (batched) ausgeführt werden sollen, bis ein Updatebefehl ausgegeben wird.

Sie müssen zuerst entscheiden, ob sie von IRowsetChangeImpl oder IRowsetUpdateImpl in Der Rowset-Klasse erben sollen. Je nachdem, welche dieser Methoden Implementiert werden sollen, sind die Funktionen von drei Methoden betroffen: SetData, , InsertRowsund DeleteRows.

  • Wenn Sie von IRowsetChangeImpl erben, ändert das Aufrufen dieser drei Methoden sofort den Datenspeicher.

  • Wenn Sie von IRowsetUpdateImpl erben, verzögern die Methoden Änderungen am Datenspeicher, bis Sie aufrufen Update, GetOriginalDataoder Undo. Wenn das Update mehrere Änderungen umfasst, werden sie im Batchmodus ausgeführt (beachten Sie, dass Batchänderungen erheblichen Arbeitsspeicheraufwand verursachen können).

Beachten Sie, dass IRowsetUpdateImpl von IRowsetChangeImpl. IRowsetUpdateImpl So erhalten Sie eine Änderungsfunktion plus Batchfunktion.

So unterstützen Sie die Updatability in Ihrem Anbieter

  1. Erben Sie in Der Rowset-Klasse von IRowsetChangeImpl oder IRowsetUpdateImpl. Diese Klassen stellen geeignete Schnittstellen zum Ändern des Datenspeichers bereit:

    Hinzufügen von IRowsetChange

    Fügen Sie ihre Vererbungskette mithilfe dieses Formulars hinzu IRowsetChangeImpl :

    IRowsetChangeImpl< rowset-name, storage-name >
    

    Fügen Sie außerdem dem BEGIN_COM_MAP Abschnitt in der Rowsetklasse hinzuCOM_INTERFACE_ENTRY(IRowsetChange).

    Hinzufügen von IRowsetUpdate

    Fügen Sie ihre Vererbungskette mithilfe dieses Formulars hinzu IRowsetUpdate :

    IRowsetUpdateImpl< rowset-name, storage>
    

    Hinweis

    Sie sollten die IRowsetChangeImpl Linie aus Ihrer Vererbungskette entfernen. Diese ausnahme der zuvor erwähnten Direktive muss den Code enthalten für IRowsetChangeImpl.

  2. Fügen Sie Folgendes zu Ihrer COM-Karte hinzu (BEGIN_COM_MAP ... END_COM_MAP):

    Wenn Sie implementieren Zu COM-Zuordnung hinzufügen
    IRowsetChangeImpl COM_INTERFACE_ENTRY(IRowsetChange)
    IRowsetUpdateImpl COM_INTERFACE_ENTRY(IRowsetUpdate)
    Wenn Sie implementieren Zur Eigenschaftensatzzuordnung hinzufügen
    IRowsetChangeImpl PROPERTY_INFO_ENTRY_VALUE(IRowsetChange, VARIANT_FALSE)
    IRowsetUpdateImpl PROPERTY_INFO_ENTRY_VALUE(IRowsetUpdate, VARIANT_FALSE)
  3. Fügen Sie in Ihrem Befehl folgendes zu Ihrer Eigenschaftensatzzuordnung hinzu (BEGIN_PROPSET_MAP ... END_PROPSET_MAP):

    Wenn Sie implementieren Zur Eigenschaftensatzzuordnung hinzufügen
    IRowsetChangeImpl PROPERTY_INFO_ENTRY_VALUE(IRowsetChange, VARIANT_FALSE)
    IRowsetUpdateImpl PROPERTY_INFO_ENTRY_VALUE(IRowsetChange, VARIANT_FALSE)PROPERTY_INFO_ENTRY_VALUE(IRowsetUpdate, VARIANT_FALSE)
  4. In Der Eigenschaftensatzzuordnung sollten Sie auch alle folgenden Einstellungen enthalten, wie sie unten angezeigt werden:

    PROPERTY_INFO_ENTRY_VALUE(UPDATABILITY, DBPROPVAL_UP_CHANGE |
      DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE)
    PROPERTY_INFO_ENTRY_VALUE(CHANGEINSERTEDROWS, VARIANT_TRUE)
    PROPERTY_INFO_ENTRY_VALUE(IMMOBILEROWS, VARIANT_TRUE)
    
    PROPERTY_INFO_ENTRY_EX(OWNINSERT, VT_BOOL, DBPROPFLAGS_ROWSET |
      DBPROPFLAGS_READ, VARIANT_TRUE, 0)
    PROPERTY_INFO_ENTRY_EX(OWNUPDATEDELETE, VT_BOOL, DBPROPFLAGS_ROWSET |
      DBPROPFLAGS_READ, VARIANT_TRUE, 0)
    PROPERTY_INFO_ENTRY_EX(OTHERINSERT, VT_BOOL, DBPROPFLAGS_ROWSET |
      DBPROPFLAGS_READ, VARIANT_TRUE, 0)
    PROPERTY_INFO_ENTRY_EX(OTHERUPDATEDELETE, VT_BOOL, DBPROPFLAGS_ROWSET |
      DBPROPFLAGS_READ, VARIANT_TRUE, 0)
    PROPERTY_INFO_ENTRY_EX(REMOVEDELETED, VT_BOOL, DBPROPFLAGS_ROWSET |
      DBPROPFLAGS_READ, VARIANT_FALSE, 0)
    

    Sie finden die in diesen Makroaufrufen verwendeten Werte, indem Sie in Atldb.h nach den Eigenschaften-IDs und -Werten suchen (wenn Atldb.h sich von der Onlinedokumentation unterscheidet, ersetzt Atldb.h die Dokumentation).

    Hinweis

    Viele der VARIANT_FALSE Einstellungen sind VARIANT_TRUE von den OLE DB-Vorlagen erforderlich. Die OLE DB-Spezifikation gibt an, dass sie lese-/schreibgeschützt sein können, aber die OLE DB-Vorlagen können nur einen Wert unterstützen.

    Wenn Sie IRowsetChangeImpl implementieren

    Wenn Sie implementieren IRowsetChangeImpl, müssen Sie die folgenden Eigenschaften für Ihren Anbieter festlegen. Diese Eigenschaften werden in erster Linie verwendet, um Schnittstellen über ICommandProperties::SetProperties.

    • DBPROP_IRowsetChange: Legt diese Einstellung automatisch fest DBPROP_IRowsetChange.

    • DBPROP_UPDATABILITY: Eine Bitmaske, die die unterstützten Methoden für IRowsetChange: SetData, , DeleteRowsoder InsertRow.

    • DBPROP_CHANGEINSERTEDROWS: Verbraucher können zeilenweise anrufen IRowsetChange::DeleteRows oder SetData neu eingefügte Zeilen verwenden.

    • DBPROP_IMMOBILEROWS: Das Rowset ordnet eingefügte oder aktualisierte Zeilen nicht neu an.

    Wenn Sie IRowsetUpdateImpl implementieren

    Wenn Sie implementieren IRowsetUpdateImpl, müssen Sie die folgenden Eigenschaften für Ihren Anbieter festlegen, zusätzlich zum Festlegen aller Eigenschaften für IRowsetChangeImpl zuvor aufgeführte:

    • DBPROP_IRowsetUpdate.

    • DBPROP_OWNINSERT: Muss READ_ONLY UND VARIANT_TRUE sein.

    • DBPROP_OWNUPDATEDELETE: Muss READ_ONLY UND VARIANT_TRUE sein.

    • DBPROP_OTHERINSERT: Muss READ_ONLY UND VARIANT_TRUE sein.

    • DBPROP_OTHERUPDATEDELETE: Muss READ_ONLY UND VARIANT_TRUE sein.

    • DBPROP_REMOVEDELETED: Muss READ_ONLY UND VARIANT_TRUE sein.

    • DBPROP_MAXPENDINGROWS.

    Hinweis

    Wenn Sie Benachrichtigungen unterstützen, verfügen Sie möglicherweise auch über einige andere Eigenschaften. weitere Informationen finden Sie im Abschnitt IRowsetNotifyCP zu dieser Liste.

Schreiben in die Datenquelle

Rufen Sie die Execute Funktion auf, um aus der Datenquelle zu lesen. Rufen Sie die FlushData Funktion auf, um in die Datenquelle zu schreiben. (Im Allgemeinen bedeutet "Leeren" das Speichern von Änderungen, die Sie an einer Tabelle oder einem Index auf einem Datenträger vornehmen.)

FlushData(HROW, HACCESSOR);

Mit den Argumenten HROW (Row Handle) und Accessor handle (HACCESSOR) können Sie den zu schreibenden Bereich angeben. In der Regel schreiben Sie jeweils ein einzelnes Datenfeld.

Die FlushData Methode schreibt Daten in das Format, in dem sie ursprünglich gespeichert wurde. Wenn Sie diese Funktion nicht außer Kraft setzen, funktioniert ihr Anbieter ordnungsgemäß, änderungen werden jedoch nicht in den Datenspeicher geleert.

Wann soll geleert werden?

Die Anbietervorlagen rufen FlushData auf, wenn Daten in den Datenspeicher geschrieben werden müssen; dies tritt in der Regel (aber nicht immer) als Ergebnis von Aufrufen der folgenden Funktionen auf:

  • IRowsetChange::DeleteRows

  • IRowsetChange::SetData

  • IRowsetChange::InsertRows (wenn neue Daten in die Zeile eingefügt werden sollen)

  • IRowsetUpdate::Update

Ein Blick hinter die Kulissen

Der Verbraucher führt einen Anruf aus, der eine Spülung erfordert (z. B. Update), und dieser Aufruf wird an den Anbieter übergeben, der immer Folgendes ausführt:

  • Aufrufe SetDBStatus , wenn ein Statuswert gebunden ist.

  • Überprüft Spaltenkennzeichnungen.

  • Ruft IsUpdateAllowed.

Diese drei Schritte tragen zur Sicherheit bei. Dann ruft der Anbieter auf FlushData.

Implementieren von FlushData

Zur Implementierung FlushDatamüssen Sie mehrere Probleme berücksichtigen:

Stellen Sie sicher, dass der Datenspeicher Änderungen verarbeiten kann.

Behandeln von NULL-Werten.

Behandeln von Standardwerten.

Um Ihre eigene FlushData Methode zu implementieren, müssen Sie:

  • Wechseln Sie zu Ihrer Rowset-Klasse.

  • Fügen Sie in der Rowset-Klasse die Deklaration von:

    HRESULT FlushData(HROW, HACCESSOR)
    {
        // Insert your implementation here and return an HRESULT.
    }
    
  • Bereitstellen einer Implementierung von FlushData.

Eine gute Implementierung von FlushData Speichern nur der Zeilen und Spalten, die tatsächlich aktualisiert werden. Sie können die Parameter HROW und HACCESSOR verwenden, um die aktuelle Zeile und Spalte zu bestimmen, die zur Optimierung gespeichert wird.

In der Regel besteht die größte Herausforderung darin, mit Ihrem eigenen nativen Datenspeicher zu arbeiten. Versuchen Sie nach Möglichkeit folgendes:

  • Behalten Sie die Methode zum Schreiben in Ihren Datenspeicher so einfach wie möglich bei.

  • Behandeln Sie NULL-Werte (optional, aber empfohlen).

  • Behandeln von Standardwerten (optional, aber empfohlen).

Es empfiehlt sich, die tatsächlich angegebenen Werte im Datenspeicher für NULL und Standardwerte zu haben. Es ist am besten, wenn Sie diese Daten extrapolieren können. Andernfalls wird empfohlen, NULL- und Standardwerte nicht zuzulassen.

Das folgende Beispiel zeigt, wie FlushData in der RUpdateRowset Klasse im UpdatePV Beispiel implementiert wird (siehe Rowset.h im Beispielcode):

///////////////////////////////////////////////////////////////////////////
// class RUpdateRowset (in rowset.h)
...
HRESULT FlushData(HROW, HACCESSOR)
{
    ATLTRACE2(atlTraceDBProvider, 0, "RUpdateRowset::FlushData\n");

    USES_CONVERSION;
    enum {
        sizeOfString = 256,
        sizeOfFileName = MAX_PATH
    };
    FILE*    pFile = NULL;
    TCHAR    szString[sizeOfString];
    TCHAR    szFile[sizeOfFileName];
    errcode  err = 0;

    ObjectLock lock(this);

    // From a filename, passed in as a command text,
    // scan the file placing data in the data array.
    if (m_strCommandText == (BSTR)NULL)
    {
        ATLTRACE( "RRowsetUpdate::FlushData -- "
                  "No filename specified\n");
        return E_FAIL;
    }

    // Open the file
    _tcscpy_s(szFile, sizeOfFileName, OLE2T(m_strCommandText));
    if ((szFile[0] == _T('\0')) ||
        ((err = _tfopen_s(&pFile, &szFile[0], _T("w"))) != 0))
    {
        ATLTRACE("RUpdateRowset::FlushData -- Could not open file\n");
        return DB_E_NOTABLE;
    }

    // Iterate through the row data and store it.
    for (long l=0; l<m_rgRowData.GetSize(); l++)
    {
        CAgentMan am = m_rgRowData[l];

        _putw((int)am.dwFixed, pFile);

        if (_tcscmp(&am.szCommand[0], _T("")) != 0)
            _stprintf_s(&szString[0], _T("%s\n"), am.szCommand);
        else
            _stprintf_s(&szString[0], _T("%s\n"), _T("NULL"));
        _fputts(szString, pFile);

        if (_tcscmp(&am.szText[0], _T("")) != 0)
            _stprintf_s(&szString[0], _T("%s\n"), am.szText);
        else
            _stprintf_s(&szString[0], _T("%s\n"), _T("NULL"));
        _fputts(szString, pFile);

        if (_tcscmp(&am.szCommand2[0], _T("")) != 0)
            _stprintf_s(&szString[0], _T("%s\n"), am.szCommand2);
        else
            _stprintf_s(&szString[0], _T("%s\n"), _T("NULL"));
        _fputts(szString, pFile);

        if (_tcscmp(&am.szText2[0], _T("")) != 0)
            _stprintf_s(&szString[0], _T("%s\n"), am.szText2);
        else
            _stprintf_s(&szString[0], _T("%s\n"), _T("NULL"));
        _fputts(szString, pFile);
    }

    if (fflush(pFile) == EOF || fclose(pFile) == EOF)
    {
        ATLTRACE("RRowsetUpdate::FlushData -- "
                 "Couldn't flush or close file\n");
    }

    return S_OK;
}

Behandeln von Änderungen

Damit Ihr Anbieter Änderungen verarbeiten kann, müssen Sie zuerst sicherstellen, dass Ihr Datenspeicher (z. B. eine Textdatei oder Videodatei) über Möglichkeiten verfügt, mit denen Sie Änderungen daran vornehmen können. Wenn dies nicht der Fall ist, sollten Sie diesen Code separat vom Anbieterprojekt erstellen.

Behandeln von NULL-Daten

Es ist möglich, dass ein Endbenutzer NULL-Daten sendet. Wenn Sie NULL-Werte in Felder in der Datenquelle schreiben, können potenzielle Probleme auftreten. Stellen Sie sich eine auftragsbezogene Anwendung vor, die Werte für Ort und Postleitzahl akzeptiert; sie kann entweder oder beide Werte akzeptieren, aber keines, weil in diesem Fall die Übermittlung unmöglich wäre. Sie müssen daher bestimmte Kombinationen von NULL-Werten in Feldern einschränken, die für Ihre Anwendung sinnvoll sind.

Als Anbieterentwickler müssen Sie überlegen, wie Sie diese Daten speichern, wie Sie diese Daten aus dem Datenspeicher lesen und wie Sie dies für den Benutzer angeben. Insbesondere müssen Sie überlegen, wie Sie den Datenstatus von Rowsetdaten in der Datenquelle ändern (z. B. DataStatus = NULL). Sie entscheiden, welcher Wert zurückgegeben werden soll, wenn ein Verbraucher auf ein Feld zugreift, das einen NULL-Wert enthält.

Sehen Sie sich den Code im UpdatePV-Beispiel an; es veranschaulicht, wie ein Anbieter NULL-Daten verarbeiten kann. In UpdatePV speichert der Anbieter NULL-Daten, indem die Zeichenfolge "NULL" im Datenspeicher geschrieben wird. Wenn sie NULL-Daten aus dem Datenspeicher liest, wird diese Zeichenfolge angezeigt und dann der Puffer geleert, wodurch eine NULL-Zeichenfolge erstellt wird. Außerdem enthält sie eine Außerkraftsetzung, in der IRowsetImpl::GetDBStatus sie DBSTATUS_S_ISNULL zurückgibt, wenn dieser Datenwert leer ist.

Markieren nullabler Spalten

Wenn Sie auch Schema-Rowsets implementieren (siehe IDBSchemaRowsetImpl), sollte Ihre Implementierung im DBSCHEMA_COLUMNS-Rowset (in der Regel in Ihrem Anbieter durch CxxxSchemaColSchemaRowset gekennzeichnet) angeben, dass die Spalte nullfähig ist.

Sie müssen auch angeben, dass alle nullfähigen Spalten den DBCOLUMNFLAGS_ISNULLABLE Wert in Ihrer Version der GetColumnInfo.

Wenn Sie in der OLE DB-Vorlagenimplementierung Spalten nicht als Nullwerte markieren, geht der Anbieter davon aus, dass er einen Wert enthalten muss und dem Consumer nicht das Senden von NULL-Werten gestattet.

Das folgende Beispiel zeigt, wie die CommonGetColInfo Funktion in CUpdateCommand implementiert wird (siehe UpProvRS.cpp) in UpdatePV. Beachten Sie, wie die Spalten diese DBCOLUMNFLAGS_ISNULLABLE für nullwerte Spalten aufweisen.

/////////////////////////////////////////////////////////////////////////////
// CUpdateCommand (in UpProvRS.cpp)

ATLCOLUMNINFO* CommonGetColInfo(IUnknown* pPropsUnk, ULONG* pcCols, bool bBookmark)
{
    static ATLCOLUMNINFO _rgColumns[6];
    ULONG ulCols = 0;

    if (bBookmark)
    {
        ADD_COLUMN_ENTRY_EX(ulCols, OLESTR("Bookmark"), 0,
                            sizeof(DWORD), DBTYPE_BYTES,
                            0, 0, GUID_NULL, CAgentMan, dwBookmark,
                            DBCOLUMNFLAGS_ISBOOKMARK)
        ulCols++;
    }

    // Next set the other columns up.
    // Add a fixed length entry for OLE DB conformance testing purposes
    ADD_COLUMN_ENTRY_EX(ulCols, OLESTR("Fixed"), 1, 4, DBTYPE_UI4,
                        10, 255, GUID_NULL, CAgentMan, dwFixed,
                        DBCOLUMNFLAGS_WRITE |
                        DBCOLUMNFLAGS_ISFIXEDLENGTH)
    ulCols++;

    ADD_COLUMN_ENTRY_EX(ulCols, OLESTR("Command"), 2, 16, DBTYPE_STR,
                        255, 255, GUID_NULL, CAgentMan, szCommand,
                        DBCOLUMNFLAGS_WRITE | DBCOLUMNFLAGS_ISNULLABLE)
    ulCols++;
    ADD_COLUMN_ENTRY_EX(ulCols, OLESTR("Text"), 3, 16, DBTYPE_STR,
                        255, 255, GUID_NULL, CAgentMan, szText,
                        DBCOLUMNFLAGS_WRITE | DBCOLUMNFLAGS_ISNULLABLE)
    ulCols++;

    ADD_COLUMN_ENTRY_EX(ulCols, OLESTR("Command2"), 4, 16, DBTYPE_STR,
                        255, 255, GUID_NULL, CAgentMan, szCommand2,
                        DBCOLUMNFLAGS_WRITE | DBCOLUMNFLAGS_ISNULLABLE)
    ulCols++;
    ADD_COLUMN_ENTRY_EX(ulCols, OLESTR("Text2"), 5, 16, DBTYPE_STR,
                        255, 255, GUID_NULL, CAgentMan, szText2,
                        DBCOLUMNFLAGS_WRITE | DBCOLUMNFLAGS_ISNULLABLE)
    ulCols++;

    if (pcCols != NULL)
    {
        *pcCols = ulCols;
    }

    return _rgColumns;
}

Standardwerte

Wie bei NULL-Daten haben Sie die Verantwortung, sich mit dem Ändern von Standardwerten zu befassen.

Der Standardwert von FlushData und Execute ist, S_OK zurückzugeben. Wenn Sie diese Funktion daher nicht überschreiben, werden die Änderungen erfolgreich angezeigt (S_OK werden zurückgegeben), aber sie werden nicht an den Datenspeicher übertragen.

UpdatePV Im Beispiel (in Rowset.h) behandelt die SetDBStatus Methode Standardwerte wie folgt:

virtual HRESULT SetDBStatus(DBSTATUS* pdbStatus, CSimpleRow* pRow,
                            ATLCOLUMNINFO* pColInfo)
{
    ATLASSERT(pRow != NULL && pColInfo != NULL && pdbStatus != NULL);

    void* pData = NULL;
    char* pDefaultData = NULL;
    DWORD* pFixedData = NULL;

    switch (*pdbStatus)
    {
        case DBSTATUS_S_DEFAULT:
            pData = (void*)&m_rgRowData[pRow->m_iRowset];
            if (pColInfo->wType == DBTYPE_STR)
            {
                pDefaultData = (char*)pData + pColInfo->cbOffset;
                strcpy_s(pDefaultData, "Default");
            }
            else
            {
                pFixedData = (DWORD*)((BYTE*)pData +
                                          pColInfo->cbOffset);
                *pFixedData = 0;
                return S_OK;
            }
            break;
        case DBSTATUS_S_ISNULL:
        default:
            break;
    }
    return S_OK;
}

Spaltenkennzeichnungen

Wenn Sie Standardwerte für Ihre Spalten unterstützen, müssen Sie sie mithilfe von Metadaten in der SchemaRowset-Klasse>des <Anbieters festlegen. Legen Sie m_bColumnHasDefault = VARIANT_TRUE fest.

Sie haben auch die Verantwortung, die Spaltenkennzeichnungen festzulegen, die mit dem aufgezählten TYP DBCOLUMNFLAGS angegeben werden. Die Spaltenkennzeichen beschreiben Die Spaltenmerkmale.

In der CUpdateSessionColSchemaRowset Klasse in UpdatePV (in Session.h) wird beispielsweise die erste Spalte auf diese Weise eingerichtet:

// Set up column 1
trData[0].m_ulOrdinalPosition = 1;
trData[0].m_bIsNullable = VARIANT_FALSE;
trData[0].m_bColumnHasDefault = VARIANT_TRUE;
trData[0].m_nDataType = DBTYPE_UI4;
trData[0].m_nNumericPrecision = 10;
trData[0].m_ulColumnFlags = DBCOLUMNFLAGS_WRITE |
                            DBCOLUMNFLAGS_ISFIXEDLENGTH;
lstrcpyW(trData[0].m_szColumnDefault, OLESTR("0"));
m_rgRowData.Add(trData[0]);

Dieser Code gibt unter anderem an, dass die Spalte einen Standardwert von 0 unterstützt, schreibbar ist und dass alle Daten in der Spalte dieselbe Länge aufweisen. Wenn die Daten in einer Spalte variable Länge aufweisen sollen, würden Sie dieses Flag nicht festlegen.

Siehe auch

Erstellen eines OLE DB-Anbieters