Aracılığıyla paylaş


Güncelleştirilebilir bir Sağlayıcı Oluşturma

Visual C++ 6.0 yalnızca salt okunur sağlayıcıları destekliyordu. Visual C++.NET güncelleştirilebilir sağlayıcıları veya veri deposunu güncelleştirebilen (yazabilen) sağlayıcıları destekler. Bu konu OLE DB şablonları kullanarak nasıl güncelleştirilebilir sağlayıcılar oluşturulabileceğini açıklamaktadır.

Bu konu, çalışılabilir bir sağlayıcıyla başlamakta olduğunuzu varsaymaktadır. Güncelleştirilebilir bir sağlayıcıyı oluşturmaya ilişkin iki adım var. Önce, sağlayıcının veri deposu değişikliklerini nasıl yapacağına karar vermeniz gerekir; özellikle, değişikliklerin hemen yapılmasına veya bir güncelleştirme komutu verilene kadar ertelenmesine karar vermelisiniz. "Sağlayıcıları Güncellenebilir Hale Getirme"bölümü değişiklikleri ve sağlayıcı kodunda yapmanız gereken ayarları açıklar.

Ardından, sağlayıcınızın, tüketicinin isteyebileceği her şeyi destekleyecek işlevselliği içerdiğinden emin olmalısınız. Tüketici veri deposunu güncelleştirmek istiyorsa, sağlayıcının veri deposuna veri devam ettiren kodu içermesi gerekir. Örneğin, veri kaynağınızda bu işlemleri gerçekleştirmek için C Çalışma Zamanı Kitaplığı veya MFC'yi kullanabilirsiniz. "Veri Kaynağına Yazma" bölümü veri kaynağına nasıl yazılacağını NULL öğesini, varsayılan değerleri ve sütun bayraklarını ayarlarını ele almayı tanımlar.

Not

UpdatePV, güncelleştirilebilir bir sağlayıcı örneğidir. UpdatePV güncelleştirilebilir desteği haricinde MyProv ile aynıdır.

Sağlayıcıları Güncelleştirilebilir Hale Getirme

Bir sağlayıcıyı güncellenebilir hale getirmenin anahtarı sağlayıcınızın veri deposunda hangi işlemleri gerçekleştirmesini istediğinizin ve sağlayıcınızın bu işlemleri nasıl gerçekleştirmesini istediğinizin anlaşılmasıdır. Özellikle asıl sorun, veri deposuna yapılacak olan güncelleştirmelerin hemen mi yapılacağı yoksa bir güncelleştirme komutu verilene kadar geciktirileceği midir (yığınlanacağı mıdır).

Önce, satır kümesi sınıfınızda IRowsetChangeImpl ya da IRowsetUpdateImpl devralıp almayacağınıza karar vermeniz gerekir. Bunlardan hangilerini uygulamak istediğinize bağlı olarak, üç yöntemin işlevselliği etkilenecektir: SetData, InsertRows ve DeleteRows.

  • IRowsetChangeImpl öğesinden devralıyorsanız, bu üç yöntemi çağırmak veri deposunu hemen değiştirir.

  • IRowsetUpdateImpl öğesinden devralıyorsanız, yöntemler siz Update, GetOriginalData veya Undo öğesini çağırana dek veri deposuna değişiklikleri erteler. Güncelleştirme birkaç değişiklik gerektiriyorsa, bunlar toplu modda gerçekleştirilir (toplu iş değişikliklerinin önemli ölçüde bellek yükü ekleyebileceğini unutmayın).

IRowsetUpdateImpl öğesinin IRowsetChangeImpl öğesinden türediğini unutmayın. Bu durumda IRowsetUpdateImpl değişim yeteneğini artı toplu iş yeteneğini verir.

Sağlayıcınızdaki güncelleştirilebilmeyi desteklemek için

  1. Satır kümesi sınıfınızda IRowsetChangeImpl veya IRowsetUpdateImpl öğesinden devralın. Bu sınıflar, veri deposunu değiştirmeye ilişkin uygun arabirimler sağlar:

    IRowsetChange Ekleme

    Bu formu kullanarak IRowsetChangeImpl başvurusunu kalıtım zincirinize ekleyin:

    IRowsetChangeImpl< rowset-name, storage-name >
    

    Ayrıca COM_INTERFACE_ENTRY(IRowsetChange)'yi satır kümesi sınıfınızdaki BEGIN_COM_MAP bölümüne ekleyin.

    IRowsetUpdate Ekleme

    Bu formu kullanarak IRowsetUpdate başvurusunu kalıtım zincirinize ekleyin:

    IRowsetUpdateImpl< rowset-name, storage>
    

    Not

    Miras zincirinizden IRowsetChangeImpl satırını kaldırmanız gerekir. Daha önce bahsedilmiş yönergeye bu tek istisna IRowsetChangeImpl öğesi için kod içermelidir.

  2. Aşağıdaki başvuruları COM haritanıza ekleyin (BEGIN_COM_MAP ... END_COM_MAP):

    Uygularsanız

    COM Haritasına Ekleyin

    IRowsetChangeImpl

    COM_INTERFACE_ENTRY(IRowsetChange)

    IRowsetUpdateImpl

    COM_INTERFACE_ENTRY(IRowsetChange)COM_INTERFACE_ENTRY(IRowsetUpdate)

  3. Komutunuza aşağıdaki özellik kümesi eşlemesini ekleyin (BEGIN_PROPSET_MAP... END_PROPSET_MAP):

    Uygularsanız

    Özellik kümesi haritasına ekleyin

    IRowsetChangeImpl

    PROPERTY_INFO_ENTRY_VALUE(IRowsetChange, VARIANT_FALSE)

    IRowsetUpdateImpl

    PROPERTY_INFO_ENTRY_VALUE(IRowsetChange, VARIANT_FALSE)PROPERTY_INFO_ENTRY_VALUE(IRowsetUpdate, VARIANT_FALSE)

  4. Özellik ayarı eşlemenize aynı zamanda aşağıdaki ayarları göründükleri şekilde eklemelisiniz:

    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)
    

    Özellik kimlikleri ve değerler için Atldb.h içine bakarak bu makro çağrılarında kullanılan değerleri bulabilirsiniz (Atldb.h çevrimiçi belgelerden farklıysa Atldb.h belgeleri çevrimiçi belgelerin yerini alır).

    Not

    VARIANT_FALSE ve VARIANT_TRUE ayarlarının birçoğu OLE DB şablonları için gereklidir; OLE DB belirtiminde bunların okunabilir/yazılabilir olduğu, ancak OLE DB şablonlarının yalnızca bir değeri destekleyebildiği söylenmektedir.

    IRowsetChangeImpl uygularsanız

    IRowsetChangeImpl öğesini uygularsanız, sağlayıcınız üzerinde aşağıdaki özellikleri ayarlamanız gerekir. Bu özellikler, öncelikli olarak ICommandProperties::SetProperties öğesi aracılığıyla arabirimler istemek için kullanılır.

    • DBPROP_IRowsetChange: Bunu otomatik olarak ayarlamak DBPROP_IRowsetChange özelliğini düzenler.

    • DBPROP_UPDATABILITY: IRowsetChange üzerindeki desteklenen yöntemleri belirten bir bit maskesi: SetData, DeleteRows veya InsertRow.

    • DBPROP_CHANGEINSERTEDROWS: Tüketici yeni eklenen satırlar için IRowsetChange::DeleteRows veya SetData çağırır.

    • DBPROP_IMMOBILEROWS: Satır kümesi eklenen veya güncelleştirilen satır yeniden düzenlemez.

    IRowsetUpdateImpl uygularsanız

    IRowsetUpdateImpl öğesini uygularsanız, sağlayıcınız üzerinde önceden listelenen IRowsetChangeImpl öğesinin bütün özelliklerini ayarlamanın yanı sıra aşağıdaki özellikleri de ayarlamanız gerekir:

    • DBPROP_IRowsetUpdate.

    • DBPROP_OWNINSERT: READ_ONLY VE VARIANT_TRUE olmalıdır.

    • DBPROP_OWNUPDATEDELETE: READ_ONLY VE VARIANT_TRUE olmalıdır.

    • DBPROP_OTHERINSERT: READ_ONLY VE VARIANT_TRUE olmalıdır.

    • DBPROP_OTHERUPDATEDELETE: READ_ONLY VE VARIANT_TRUE olmalıdır.

    • DBPROP_REMOVEDELETED: READ_ONLY VE VARIANT_TRUE olmalıdır.

    • DBPROP_MAXPENDINGROWS.

      Not

      Bildirimleri destekliyorsanız, bazı başka özelliklere de sahip olabilirsiniz, bu liste için IRowsetNotifyCP öğesindeki bölüme bakın.

    Özelliklerin nasıl ayarlandığına yönelik bir örnek için, UpdatePV üzerindeki CUpdateCommand (Satır kümesi içinde) içindeki özellik ayarı eşlemesine bakın.

Veri Kaynağına Yazma

Veri kaynağından okumak için Yürüt işlevini çağırın. Veri kaynağına yazmak için FlushData işlevini çağırın. (Genel olarak, temizleme bir tablo veya dizinde yaptığınız değişiklikleri kaydetmeniz anlamına gelir.)

FlushData(HROW, HACCESSOR);

Satır işleyici (HROW) ve erişimci işleyici (HACCESSOR) bağımsız değişkenleri, yazılacak bölgeyi belirlemenize izin verir. Genellikle her seferinde tek bir veri alanı yazarsınız.

FlushData yöntemi veriyi özgün olarak saklandığı biçiminde yazar. Bu işlevi geçersiz kılmazsanız sağlayıcınız düzgün çalışacak ancak değişiklikler veri deposuna temizlenmeyecektir.

Hangi Durumlarda Temizleme Yapılır

Veri deposuna veri yazılması gerektiğinde sağlayıcı şablonları FlushData öğesini arar, genelde (her zaman değil) aşağıdaki işlevlere ilişkin çağrıların sonucu olarak meydana gelir:

  • IRowsetChange::DeleteRows

  • IRowsetChange::setData

  • IRowsetChange::InsertRows (satıra eklemek için yeni veriler varsa)

  • IRowsetUpdate::Update

Nasıl Çalışır?

Tüketici ( Güncelleştirgibi) temizleme gerektiren bir çağrı yapar ve bu çağrı daima aşağıdakileri yapan sağlayıcıya geçirilir:

  • Bağlı bir durum değerine sahip olduğunuzda SetDBStatus öğesini çağırır (bkz. OLE DB Programcı Başvurusu, Bölüm 6, Veri Bölümleri: Durum).

  • Sütun bayraklarını denetler.

  • IsUpdateAllowed'i çağırır.

Şu üç adım güvenliğini sağlamaya yardım eder. Ardından sağlayıcı FlushData öğesini çağırır.

FlushData Nasıl Uygulanır

FlushData öğesini uygulamak için bir kaç sorunu göz önüne almanız gerekir:

  • Veri deposunun değişiklikleri işleyebildiğinden emin olma.

  • NULL değerleri işliyor.

  • Varsayılan değerleri işliyor.

Kendi FlushData yönteminizi uygulamak için şunu yapmanız gerekir:

  • Satır kümesi sınıfınıza gidin.

  • Satır kümesi sınıfına şunun bildirimini koyun:

   HRESULT FlushData(HROW, HACCESSOR)
   {
       // Insert your implementation here and return an HRESULT.
   }
  • FlushData öğesi için uygulama sağlayın.

FlushData başvurusunun iyi uygulanması, aslında yalnızca güncellenen satırları ve sütunları depolar. HROW ve HACCESSOR parametrelerini optimizasyon için depolanan geçerli satır ve sütunu belirlemek üzere kullanabilirsiniz.

Genellikle en büyük zorluk kendi yerel veri deponuzla çalışmaktır. Mümkünse, deneyin:

  • Veri deponuza yazma yöntemini mümkün olduğunda basit tutun.

  • NULL değerlerini işle (isteğe bağlı, ancak tavsiye edilir).

  • Varsayılan değerleri işle (isteğe bağlı, ancak tavsiye edilir).

Yapılacak en iyi şey, NULL ve varsayılan değerler için veri deponuzda gerçek belirtilmiş değerlerin olmasıdır. Bu verileri tahmin edebilmek en iyisidir. Aksi durumda, NULL ve varsayılan değerlere izin vermemeniz tavsiye edilir.

Aşağıdaki örnek FlushData öğesinin UpdatePV örneğindeki (bkz. örnek kodda Rowset.h) RUpdateRowset sınıfında nasıl uygulandığını gösterir.

///////////////////////////////////////////////////////////////////////////
// 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;
}

Değişiklikleri İşliyor

Sağlayıcınızın değişiklikleri işlemesi için, öncelikle veri deponuzun (örneğin, metin dosyası veya video dosyası) üzerinde değişiklik yapmanızı sağlayan olanaklara sahip olduğundan emin olmalısınız. Yoksa, bu kodu sağlayıcı projesinden ayrı oluşturmalısınız.

NULL Verileri İşliyor

Son kullanıcının NULL veri göndermesi mümkündür. Veri kaynağındaki alanlara null değerler yazdığınızda, olası sorunlar olabilir. Şehir ve posta kodu değerlerini kabul eden bir sipariş alma uygulaması düşünün; değerlerin birini veya her ikisini kabul edebilir, ama teslimat imkansız olacağından değerlerden hiçbirini kabul etmemesi olanaksızdır. Bu nedenle uygulamanızı anlamlı yapan alanlarda NULL değerlerinin belirli birleşimlerini kısıtlamak zorundasınız.

Sağlayıcı geliştiricisi olarak, o veriyi nasıl depolayacağınızı, o veriyi veri deposundan nasıl okuyacağınızı ve onu kullanıcıya nasıl belirteceğinizi göz önünde bulundurmanız gerekir. Özellikle, veri kaynağında satır kümesi verisinin veri durumunu nasıl değiştireceğinizi düşünmeniz gerekir (örneğin, DataStatus = NULL). Tüketici NULL değeri içeren bir alana eriştiğinde hangi değerin döndürüleceğine karar verin.

UpdatePV örneğindeki koda bakın; bu kod, bir sağlayıcının NULL verilerini nasıl ele aldığını gösterir. UpdatePV öğesinde sağlayıcı Null verisini veri deposuna "NULL" dizesini yazarak depolar. Veri deposundan NULL verisini okuduğunda, o dizeyi görür ve ardından bir NULL dizesi oluşturarak arabelleği boşaltır. Ayrıca bir IRowsetImpl::GetDBStatus geçersiz kılması bulunur. Bu geçersiz kılmada veri değeri boşsa DBSTATUS_S_ISNULL döndürür.

Boş Değer Atanabilir Sütunları İşaretleme

Şema satır kümelerini de uygularsanız (bkz: IDBSchemaRowsetImpl), uygulamanızın DBSCHEMA_COLUMNS satır kümesinde sütunun null değeri alabilecek olduğunu belirtmesi gerekir (genellikle sağlayıcınız tarafından CxxxSchemaColSchemaRowset olarak işaretlenir)

Ayrıca, sizin GetColumnInfo sürümünüzde null değeri alabilen tüm sütunların DBCOLUMNFLAGS_ISNULLABLE değerini içerdiğini belirtmeniz gerekir.

OLE DB şablon uygulamasında sütunları null olabilir olarak işaretlemezseniz, sağlayıcı bunların bir değer içermesi gerektiğini varsayar ve tüketicinin bunlara null değerler göndermesine izin vermez.

Aşağıdaki örnek CommonGetColInfo işlevinin UpdatePV'deki CUpdateCommand öğesinde (bkz. UpProvRS.cpp) nasıl uygulandığını gösterir. Sütunların boş değer atanabilir sütunlar için bu DBCOLUMNFLAGS_ISNULLABLE değerine nasıl sahip olduğuna dikkat edin.

/////////////////////////////////////////////////////////////////////////////
// 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;
}

Varsayılan Değerler

NULL verilerinde olduğu gibi, değişen varsayılan değerlerle başa çıkma sorumluluğunuz vardır.

FlushData ve Yürüt öğelerinin varsayılanı S_OK öğesini döndürmek içindir. Bu yüzden, bu işlevi geçersiz kılmazsanız değişiklikler başarılı görünür (S_OK öğesine döndürülür), ancak veri deposuna aktarılmaz.

UpdatePV örneğinde (Rowset.h), SetDBStatus yöntemi varsayılan değerleri aşağıdaki gibi işler:

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;
}

Sütun Bayrakları

Sütunlar üzerinde varsayılan değerleri destekliyorsa, <sağlayıcı sınıfı> SchemaRowset sınıfındaki meta verileri kullanarak ayarlamanız gerekebilir. m_bColumnHasDefault = VARIANT_TRUE olarak ayarlayın.

Ayrıca, DBCOLUMNFLAGS numaralandırılmış türü kullanılarak belirtilen sütun bayraklarını ayarlama sorumluluğuna da sahipsinizdir. Sütun bayrakları sütun özelliklerini açıklar.

Örneğin, UpdatePV (Session.h üzerinde) üzerindeki CUpdateSessionColSchemaRowset sınıfında, ilk sütun aşağıdaki şekilde ayarlanır:

// 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]);

Bu kod, bu arada, sütunun yazılabilen bir varsayılan 0 değerini desteklediğini ve sütundaki tüm verinin aynı uzunluğu içerdiğini belirtir. Bir sütundaki verinin değişken uzunluğa sahip olmasını istiyorsanız, bu bayrağı ayarlamazsınız.

Ayrıca bkz.

Başvuru

OLE DB Sağlayıcısı Oluşturma