İngilizce dilinde oku

Aracılığıyla paylaş


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

Visual C++, veri depolarını güncelleştirebilen (yazabilen) güncelleştirilebilir sağlayıcıları veya sağlayıcıları destekler. Bu konuda, OLE DB şablonlarını kullanarak güncelleştirilebilir sağlayıcıların nasıl oluşturulacağı açıklanır.

Bu konu başlığında, çalışılabilir bir sağlayıcıyla başladığınız varsayılır. Güncelleştirilebilir sağlayıcı oluşturmanın iki adımı vardır. Önce sağlayıcının veri deposunda nasıl değişiklik yapacağına karar vermelisiniz; özellikle, bir güncelleştirme komutu verilene kadar değişikliklerin hemen mi yoksa ertelenerek mi yapılacağını belirtin. "Sağlayıcıları Güncelleştirilebilir Hale Getirme" bölümünde, sağlayıcı kodunda yapmanız gereken değişiklikler ve ayarlar açıklanmaktadır.

Ardından, sağlayıcınızın tüketicinin istediği her şeyi destekleyecek tüm işlevleri içerdiğinden emin olmanız gerekir. Tüketici veri depoyu güncelleştirmek istiyorsa, sağlayıcının verileri veri deposunda kalıcı hale getiren kod içermesi gerekir. Örneğin, veri kaynağınızda bu tür işlemleri gerçekleştirmek için C Çalışma Zamanı Kitaplığı'nı veya MFC'yi kullanabilirsiniz. "Veri Kaynağına Yazma" bölümünde veri kaynağına yazma, NULL ve varsayılan değerlerle ilgilenme ve sütun bayraklarını ayarlama işlemleri açıklanır.

Not

UpdatePV , güncelleştirilebilir bir sağlayıcı örneğidir. UpdatePV, MyProv ile aynıdır ancak güncelleştirilebilir destek içerir.

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

Sağlayıcıyı güncelleştirilebilir hale getirmenin anahtarı, sağlayıcınızın veri deposunda gerçekleştirmesini istediğiniz işlemleri ve sağlayıcının bu işlemleri nasıl gerçekleştirmesini istediğinizi anlamaktır. Özellikle, önemli sorun veri deposu güncelleştirmelerinin bir güncelleştirme komutu verilene kadar hemen mi yoksa ertelenmiş mi (toplu) olarak yapılmasıdır.

Önce satır kümesi sınıfınızdan mı IRowsetUpdateImpl yoksa sınıfından IRowsetChangeImpl mı devralmaya karar vermelisiniz. Bunlardan hangisini uygulamayı seçtiğinize bağlı olarak, üç yöntemin işlevselliği etkilenir: SetData, InsertRowsve DeleteRows.

  • IRowsetChangeImpl'den devralırsanız, bu üç yöntemin çağrılması veri depoyu hemen değiştirir.

  • IRowsetUpdateImpl'den devralırsanız, yöntemler , GetOriginalDataveya Undoçağrılana Updatekadar veri deposuna yapılan değişiklikleri erteler. Güncelleştirme birkaç değişiklik içeriyorsa, bunlar toplu iş modunda gerçekleştirilir (toplu işlem değişikliklerinin önemli bellek yükü ekleyebileceğini unutmayın).

öğesinin türetildiğini IRowsetUpdateImpl IRowsetChangeImplunutmayın. Böylece, IRowsetUpdateImpl değişiklik özelliğine ek olarak toplu iş özelliği sağlar.

Sağlayıcınızda güncelleştirilebilirliği desteklemek için

  1. Satır kümesi sınıfınızda veya IRowsetUpdateImplöğesinden IRowsetChangeImpl devralın. Bu sınıflar, veri depolarını değiştirmek için uygun arabirimler sağlar:

    IRowsetChange Ekleme

    Bu formu kullanarak devralma zincirinize ekleyin IRowsetChangeImpl :

    IRowsetChangeImpl< rowset-name, storage-name >
    

    Satır kümesi sınıfınızdaki bölüme BEGIN_COM_MAP de ekleyinCOM_INTERFACE_ENTRY(IRowsetChange).

    IRowsetUpdate Ekleme

    Bu formu kullanarak devralma zincirinize ekleyin IRowsetUpdate :

    IRowsetUpdateImpl< rowset-name, storage>
    

    Not

    Satırı devralma zincirinizden kaldırmanız IRowsetChangeImpl gerekir. Daha önce bahsedilen yönergenin bu özel durumu için IRowsetChangeImplkodunu içermelidir.

  2. COM haritanıza aşağıdakileri ekleyin (BEGIN_COM_MAP ... END_COM_MAP):

    Uygularsanız COM haritasına ekle
    IRowsetChangeImpl COM_INTERFACE_ENTRY(IRowsetChange)
    IRowsetUpdateImpl COM_INTERFACE_ENTRY(IRowsetUpdate)
    Uygularsanız Özellik kümesi eşlemesine ekle
    IRowsetChangeImpl PROPERTY_INFO_ENTRY_VALUE(IRowsetChange, VARIANT_FALSE)
    IRowsetUpdateImpl PROPERTY_INFO_ENTRY_VALUE(IRowsetUpdate, VARIANT_FALSE)
  3. Komutunuzda, aşağıdakileri özellik kümesi eşlemenize (BEGIN_PROPSET_MAP ... END_PROPSET_MAP) ekleyin:

    Uygularsanız Özellik kümesi eşlemesine ekle
    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 kümesi haritanızda aşağıdaki ayarların tümünü aşağıda gösterildiği gibi de 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ğerleri için Atldb.h'ye bakarak bu makro çağrılarında kullanılan değerleri bulabilirsiniz (Atldb.h çevrimiçi belgelerden farklıysa, Atldb.h belgelerin yerini alır).

    Not

    VE VARIANT_TRUE ayarlarının VARIANT_FALSE çoğu OLE DB şablonları için gereklidir; OLE DB belirtimi okunabilir/yazılabilir olduğunu belirtir, ancak OLE DB şablonları yalnızca bir değeri destekleyebilir.

    IRowsetChangeImpl uygularsanız

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

    • DBPROP_IRowsetChange: Bu ayar otomatik olarak ayarlanır DBPROP_IRowsetChange.

    • DBPROP_UPDATABILITY: , veya InsertRowüzerinde IRowsetChangeSetDataDeleteRowsdesteklenen yöntemleri belirten bir bit maskesi.

    • DBPROP_CHANGEINSERTEDROWS: Tüketici, yeni eklenen satırları çağırabilir IRowsetChange::DeleteRows veya SetData çağırabilir.

    • DBPROP_IMMOBILEROWS: Satır kümesi eklenen veya güncelleştirilen satırları yeniden sıralamaz.

    IRowsetUpdateImpl uygularsanız

    uygularsanız IRowsetUpdateImpl, daha önce listelenen tüm özellikleri ayarlamanın yanı sıra sağlayıcınızda aşağıdaki özellikleri IRowsetChangeImpl 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 özellikleriniz de olabilir; bu listenin üzerindeki IRowsetNotifyCP bölümüne bakın.

Veri Kaynağına Yazma

Veri kaynağından okumak için işlevini çağırın Execute . Veri kaynağına yazmak için işlevini çağırın FlushData . (Genel olarak, temizleme, bir tabloda veya dizinde yaptığınız değişiklikleri diske kaydetmek anlamına gelir.)

FlushData(HROW, HACCESSOR);

Satır tutamacı (HROW) ve erişimci tutamacı (HACCESSOR) bağımsız değişkenleri, yazılacak bölgeyi belirtmenize olanak sağlar. Genellikle tek seferde tek bir veri alanı yazarsınız.

FlushData yöntemi, verileri ilk olarak depolandığı biçimde yazar. Bu işlevi geçersiz kılmazsanız, sağlayıcınız düzgün çalışır ancak değişiklikler veri deposuna boşaltılmaz.

Ne Zaman Boşaltılı?

Sağlayıcı şablonları, verilerin veri deposuna yazılması gerektiğinde FlushData'yı çağırır; bu genellikle (ancak her zaman değil) aşağıdaki işlevlere yapılan çağrıların bir sonucu olarak gerçekleşir:

  • IRowsetChange::DeleteRows

  • IRowsetChange::SetData

  • IRowsetChange::InsertRows (satıra eklenecek yeni veriler varsa)

  • IRowsetUpdate::Update

Nasıl Çalışır?

Tüketici, temizleme (Güncelleştirme gibi) gerektiren bir çağrı yapar ve bu çağrı sağlayıcıya geçirilir ve her zaman aşağıdakileri yapar:

  • Durum değeri bağlı olduğunda çağrılar SetDBStatus .

  • Sütun bayraklarını denetler.

  • IsUpdateAllowed çağrısı yapar.

Bu üç adım güvenliği sağlamaya yardımcı olur. Ardından sağlayıcı öğesini çağırır FlushData.

FlushData Uygulama

uygulamasını uygulamak FlushDataiçin birkaç sorunu dikkate almanız gerekir:

Veri deposunun değişiklikleri işleyebileceğinden emin olun.

NULL değerleri işleme.

Varsayılan değerleri işleme.

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

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

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

    HRESULT FlushData(HROW, HACCESSOR)
    {
        // Insert your implementation here and return an HRESULT.
    }
    
  • uygulamasını FlushDatasağlayın.

İyi bir uygulama yalnızca FlushData gerçekten güncelleştirilen satırları ve sütunları depolar. İyileştirme için depolanmakta olan geçerli satırı ve sütunu belirlemek için HROW ve HACCESSOR parametrelerini kullanabilirsiniz.

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

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

  • NULL değerlerini işleyebilir (isteğe bağlı ancak önerilen).

  • Varsayılan değerleri işleyebilir (isteğe bağlı ancak önerilen).

Yapılacak en iyi şey, veri deponuzda NULL ve varsayılan değerler için gerçek belirtilen değerlere sahip olmaktır. Bu verileri tahmin etmeniz en iyisidir. Aksi takdirde NULL ve varsayılan değerlere izin vermemeye dikkat edin.

Aşağıdaki örnekte, örnekteki RUpdateRowset sınıfında UpdatePV nasıl FlushData uygulandığı gösterilmektedir (örnek kodda Rowset.h bölümüne bakın):

///////////////////////////////////////////////////////////////////////////
// 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 İşleme

Sağlayıcınızın değişiklikleri işleyebilmesi için öncelikle veri deponuzda (metin dosyası veya video dosyası gibi) üzerinde değişiklik yapmanıza olanak tanıyan olanaklar olduğundan emin olmanız gerekir. Aksi takdirde, bu kodu sağlayıcı projesinden ayrı olarak oluşturmanız gerekir.

NULL Verileri İşleme

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; ya da her iki değeri de kabul edebilir, ancak hiçbirini kabul etmeyebilir, çünkü bu durumda teslim mümkün olmazdı. Bu nedenle, uygulamanız için anlamlı olan alanlardaki null değerlerin belirli birleşimlerini kısıtlamanız gerekir.

Sağlayıcı geliştiricisi olarak bu verileri nasıl depolayabileceğinizi, bu verileri veri deposundan nasıl okuyabileceğinizi ve bunu kullanıcıya nasıl belirttiğinizi göz önünde bulundurmanız gerekir. Özellikle, veri kaynağındaki satır kümesi verilerinin veri durumunun nasıl değiştirileceğini göz önünde bulundurmanız gerekir (örneğin, DataStatus = NULL). Bir tüketici NULL değeri içeren bir alana eriştiğinde hangi değerin döndürüleceğine siz karar verirsiniz.

UpdatePV örneğindeki koda bakın; bir sağlayıcının NULL verileri nasıl işleyebileceğini gösterir. UpdatePV'de sağlayıcı, veri deposunda "NULL" dizesini yazarak NULL verileri depolar. Veri deposundan NULL verileri okuduğunda, bu dizeyi görür ve ardından boş bir dize oluşturarak arabelleği boşaltabilir. Ayrıca, veri değeri boşsa DBSTATUS_S_ISNULL döndürdüğü geçersiz kılmaya IRowsetImpl::GetDBStatus da sahiptir.

Null Atanabilir Sütunları İşaretleme

Şema satır kümelerini de uygularsanız (bkz IDBSchemaRowsetImpl. ) uygulamanız DBSCHEMA_COLUMNS satır kümesinde (genellikle CxxxSchemaColSchemaRowset tarafından işaretlenmiştir) sütunun null atanabilir olduğunu belirtmelidir.

Ayrıca, tüm null atanabilir sütunların sürümünüzdeki DBCOLUMNFLAGS_ISNULLABLE değerini içermesini GetColumnInfobelirtmeniz gerekir.

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

Aşağıdaki örnek, işlevin CommonGetColInfo UpdatePV'deki CUpdateCommand'da nasıl uygulandığını gösterir (bkz. UpProvRS.cpp). Sütunların null atanabilir sütunlar için nasıl bu DBCOLUMNFLAGS_ISNULLABLE olduğunu unutmayın.

/////////////////////////////////////////////////////////////////////////////
// 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 verilerde olduğu gibi, varsayılan değerleri değiştirme sorumluluğunuz vardır.

ve Execute varsayılanı FlushData S_OK döndürmektir. Bu nedenle, bu işlevi geçersiz kılmazsanız, değişiklikler başarılı gibi görünür (S_OK döndürülür), ancak veri deposuna iletilmez.

UpdatePV Örnekte (Rowset.h dosyasında), 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ınızda varsayılan değerleri destekliyorsanız SchemaRowset sağlayıcı sınıfındaki <>meta verileri kullanarak ayarlamanız gerekir. öğesini ayarlayın m_bColumnHasDefault = VARIANT_TRUE.

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

Örneğin, CUpdateSessionColSchemaRowset içindeki UpdatePV (Session.h'de) sınıfında ilk sütun şu ş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, sütunun 0 varsayılan değerini desteklediğini, yazılabilir olduğunu ve sütundaki tüm verilerin aynı uzunlukta olduğunu belirtir. Bir sütundaki verilerin değişken uzunluğu olmasını istiyorsanız, bu bayrağı ayarlamazsınız.

Ayrıca bkz.

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