【问题标题】:SQL Server CE 3.5 update row error DB_E_ERRORSOCCURRED column error is DBSTATUS_E_SCHEMAVIOLATIONSQL Server CE 3.5 更新行错误 DB_E_ERRORSOCCURRED 列错误是 DBSTATUS_E_SCHEMAVIOLATION
【发布时间】:2014-06-20 23:57:39
【问题描述】:

我正在研究将一个小型且简单的 SQL Server 数据库迁移到 SQL Server CE,目前正在使用一个小型原型来研究 SQL Server CE 的基本操作,并考虑以下操作:(1) 以编程方式创建一个表,(2 ) 插入新记录,(3) 读取现有记录,(4) 更新现有记录。

在使用访问器和访问器结构的绑定成员时,原型在更新现有记录时遇到问题。 select 语句可以正常工作,返回行和数据。我可以更新访问器绑定的成员,但是当我使用SetData() 方法更新行时,返回的HRESULT 值是DB_E_ERRORSOCCURRED。然后我检查DBSTATUS 变量,我可以看到DBSTATUS_E_SCHEMAVIOLATION 的错误代码。

DBSTATUS_E_SCHEMAVIOLATION 是什么意思,我需要更改什么才能使SetData() 正常工作?

如果我修改 OLEDB 中使用的 SQL 查询,而不是执行 SELECT,而是执行 UPDATEUPDATEWHERE 子句选择的行被正确修改。问题似乎出在SetData() 功能和绑定逻辑上。当我用 SQL Server Express 做同样的事情时,我没有看到错误。我发现 SQL Server CE 3.5 和 SQL Server Mobile for Visual Studio 2005 出现相同的错误。

在 Visual Studio 2005 IDE 的输出窗口中,我看到以下几行。标有<<<<< ATLTRACE2 的两行是ATLTRACE2 宏的输出,用于显示各个列的状态值。根据我在 Internet 上找到的信息,First-chance 异常日志是一个可以忽略的警告。

First-chance exception at 0x7c812fd3 in dblist_ce.exe: Microsoft C++ exception: long at memory location 0x0012f698..
OLE DB Error Record dump for hr = 0x80040e21
The thread 'Win32 Thread' (0x16dc) has exited with code 0 (0x0).
Row #:    0 Source: "Microsoft Cursor Engine" Description: "Multiple-step operation generated errors. Check each status value." Help File: "(null)" Help Context:    0 GUID: {00000000-0000-0000-0000-000000000000}
OLE DB Error Record dump end
  myTable.m_dwIdNumberStatus = 8    <<<<< ATLTRACE2
  myTable.m_dwCountStatus = 11      <<<<< ATLTRACE2

这两个状态值(m_dwIdNumberStatus 和 m_dwCountStatus)具有来自枚举的值,上述两个值分别代表DBSTATUS_E_UNAVAILABLE = 8DBSTATUS_E_SCHEMAVIOLATION = 11。 IdNumber 的状态是DBSTATUS_E_UNAVAILABLE,因为我在执行SetData() 之前将其设置为被忽略。

原型的源代码如下。它的作用是在 SQL Server CE 数据库文件不存在时创建它,然后用一组行填充它,然后尝试对一个特定行进行更新。

// dblist_ce.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <string>
#include <iostream>

#define SQLSERVER_MOBILE L"Provider=Microsoft.SQLSERVER.MOBILE.OLEDB.3.0;Data Source=C:\\MyDatabase3.sdf"
#define SQLSERVER_CE_35  L"Provider=Microsoft.SQLSERVER.CE.OLEDB.3.5;Data Source=C:\\MyDatabase35.sdf"


#define SQL_SERVER_CONNECT_STRING   SQLSERVER_MOBILE
#define SQL_SERVER_CE_FILENAME     "C:\\MyDatabase3.sdf"

#if 0
#include "Table_1.h"
#else
//  contents of include file Table_1.h follow

// Table_1.h : Declaration of the CTable_1

// code generated on Saturday, April 26, 2014, 11:23 AM

class CTable_1Accessor
{
public:
    TCHAR m_IdNumber[11];
    LONG  m_Count;

    // 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_dwIdNumberStatus;
    DBSTATUS m_dwCountStatus;

    // 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_dwIdNumberLength;
    DBLENGTH m_dwCountLength;

    void GetRowsetProperties(CDBPropSet* pPropSet)
    {
        bool  bRet;
        bRet = pPropSet->AddProperty(DBPROP_CANFETCHBACKWARDS, true, DBPROPOPTIONS_OPTIONAL);
        bRet = pPropSet->AddProperty(DBPROP_CANSCROLLBACKWARDS, true, DBPROPOPTIONS_OPTIONAL);
        bRet = pPropSet->AddProperty(DBPROP_IGetRow, true, DBPROPOPTIONS_OPTIONAL);
        bRet = pPropSet->AddProperty(DBPROP_IRowsetChange, true, DBPROPOPTIONS_OPTIONAL);
        bRet = pPropSet->AddProperty(DBPROP_IRowsetUpdate, true, DBPROPOPTIONS_OPTIONAL);
        bRet = pPropSet->AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE);
    }

    HRESULT OpenDataSource()
    {
        CDataSource _db;
        HRESULT hr;
        hr = _db.OpenFromInitializationString(SQL_SERVER_CONNECT_STRING);
        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(CTable_1Accessor, L" \
    SELECT \
        IdNumber, \
        Count \
        FROM Table_1")


    // In order to fix several issues with some providers, the code below may bind
    // columns in a different order than reported by the provider

    BEGIN_COLUMN_MAP(CTable_1Accessor)
        COLUMN_ENTRY_LENGTH_STATUS(1, m_IdNumber, m_dwIdNumberLength, m_dwIdNumberStatus)
        COLUMN_ENTRY_LENGTH_STATUS(2, m_Count, m_dwCountLength, m_dwCountStatus)
    END_COLUMN_MAP()
};

class CTable_1 : public CCommand<CAccessor<CTable_1Accessor> >
{
public:
    HRESULT OpenAll()
    {
        HRESULT hr;
        hr = OpenDataSource();
        if (FAILED(hr))
            return hr;
        __if_exists(GetRowsetProperties)
        {
            CDBPropSet propset(DBPROPSET_ROWSET);
            __if_exists(HasBookmark)
            {
                if( HasBookmark() )
                    propset.AddProperty(DBPROP_IRowsetLocate, true);
            }
            GetRowsetProperties(&propset);
            return OpenRowset(&propset);
        }
        __if_not_exists(GetRowsetProperties)
        {
            __if_exists(HasBookmark)
            {
                if( 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, NULL, pPropSet);
#ifdef _DEBUG
        if(FAILED(hr))
            AtlTraceErrorRecords(hr);
#endif
        return hr;
    }

    void CloseAll()
    {
        Close();
        ReleaseCommand();
        CloseDataSource();
    }
};
// ------     End of the content from include file Table_1.h
#endif

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hrResult = OleInitialize(NULL);
    switch (hrResult)
    {
        case S_OK:
            break;
        default:
            std::cout << "Ole Initialization Failed " << hrResult << std::endl;
            return 1;
    }

    HRESULT   hr;

    CTable_1  myTable;

    bool      myTableNew = false;

    hr = myTable.OpenAll ();
    AtlTraceErrorRecords(hr);
    if (hr == S_OK) {
        int  nItem = 0;

        for (nItem = 0, hr = myTable.MoveFirst(); hr == S_OK; hr = myTable.MoveNext())
        {
            char szValueChar[12] = {0};
            for (int i = 0; i < 10; i++) szValueChar[i] = (char)myTable.m_IdNumber[i];
            std::string sTemp (szValueChar);
            std::cout << nItem << "  -> " << sTemp << " : " << myTable.m_Count << std::endl;
            nItem++;
        }
        myTable.Close();    // close this row set.
    } else if (hr == E_FAIL) {
        FILE *hFile = fopen (SQL_SERVER_CE_FILENAME, "w");
        if (hFile) {
            fclose(hFile);
            hr = myTable.OpenAll ();
            if (hr == E_FAIL)
                return 0;
        }
    }

    if (hr == DB_E_NOTABLE) {
        // The database file is empty meaning that there are no tables defined
        // so we will create the table that we want to use.
        myTable.Close();    // close this row set.

        CDBPropSet m_pPropSet(DBPROPSET_ROWSET);
        myTable.GetRowsetProperties (&m_pPropSet);

        TCHAR *tcsQuery = L"create table Table_1 ([IdNumber] nchar(10) not null, [Count] int not null)";

        hr = myTable.Open (myTable.m_session, tcsQuery, &m_pPropSet, NULL, DBGUID_DEFAULT, false);
        myTable.Close();    // close this row set.
        myTableNew = true;
    }

    CDBPropSet m_pPropSet(DBPROPSET_ROWSET);
    myTable.GetRowsetProperties (&m_pPropSet);

    TCHAR tcsQuery[256];

    if (myTableNew) {
        struct {
            TCHAR IdNumber[11];
            int   iCount;
        } myInsertData[] = {
            {L"0000000101", 1001},
            {L"0000000102", 1002},
            {L"0000000103", 1003},
            {L"0000000104", 1004},
            {L"0000000105", 1005},
            {L"0000000106", 1006},
            {L"0000000107", 1007},
            {L"0000000108", 1008},
            {L"0000000109", 1009},
            {L"0000000120", 1010}
        };

        std::cout << "--  New table so insert standard rows " << std::endl;

        for (int i = 0; i < sizeof(myInsertData)/sizeof(myInsertData[0]); i++) {
            _swprintf (tcsQuery, L"INSERT INTO Table_1 ( [IdNumber], [Count] ) VALUES ('%s', %d)", myInsertData[i].IdNumber, myInsertData[i].iCount);
            hr = myTable.Open (myTable.m_session, tcsQuery, &m_pPropSet, NULL, DBGUID_DEFAULT, false);
            myTable.Close();    // close this row set.
        }
    }

    // Lets print out a list of the rows that we currently have in the database
    wcscpy (tcsQuery, L"SELECT [IdNumber], [Count] from Table_1");
    hr = myTable.Open (myTable.m_session, tcsQuery, &m_pPropSet, NULL, DBGUID_DEFAULT, true);
    if (hr == S_OK) {
        int  nItem = 0;

        for (nItem = 0, hr = myTable.MoveFirst(); hr == S_OK; hr = myTable.MoveNext())
        {
            char szValueChar[12] = {0};
            for (int i = 0; i < 10; i++) szValueChar[i] = (char)myTable.m_IdNumber[i];
            std::string sTemp (szValueChar);
            std::cout << nItem << "  -> " << sTemp << " : " << myTable.m_Count << std::endl;
            nItem++;
        }
        myTable.Close();    // close this row set.
    }

    std::cout << " --  After insert now list the rows we have inserted" << std::endl;

    wcscpy (tcsQuery, L"SELECT [IdNumber], [Count] from Table_1 where [IdNumber] = '0000000103'");
//  wcscpy (tcsQuery, L"UPDATE Table_1 SET [Count]=[Count] + 1 where [IdNumber] = '0000000103'");
    hr = myTable.Open (myTable.m_session, tcsQuery, &m_pPropSet, NULL, DBGUID_DEFAULT, true);
    AtlTraceErrorRecords(hr);
    if (hr == S_OK) {
        if ((hr = myTable.MoveFirst()) == S_OK)
        {
            char szValueChar[12] = {0};
            for (int i = 0; i < 10; i++) szValueChar[i] = (char)myTable.m_IdNumber[i];
            std::string sTemp (szValueChar);
            std::cout << "  -> " << sTemp << " : " << myTable.m_Count << std::endl;
            int iCountTemp = myTable.m_Count++;
            std::cout << "          increment count from " << iCountTemp << " to " << myTable.m_Count << std::endl;
            myTable.m_dwIdNumberStatus = DBSTATUS_S_IGNORE;
            myTable.m_dwCountStatus = DBSTATUS_S_OK;
            hr = myTable.SetData ();
            AtlTraceErrorRecords(hr);
            if (hr != S_OK) {
                ATLTRACE2("  myTable.m_dwIdNumberStatus = %d\n", myTable.m_dwIdNumberStatus);
                ATLTRACE2("  myTable.m_dwCountStatus = %d\n", myTable.m_dwCountStatus);
                if (myTable.m_dwIdNumberStatus != DBSTATUS_S_OK) {
                    std::cout << "                error: m_dwIdNumberStatus = "<< myTable.m_dwIdNumberStatus << std::endl;
                }
                if (myTable.m_dwCountStatus != DBSTATUS_S_OK) {
                    std::cout << "                error: m_dwCountStatus = "<< myTable.m_dwCountStatus << std::endl;
                }
            }
        } else {
            AtlTraceErrorRecords(hr);
        }
    }
    myTable.Close();    // close this row set.

    OleUninitialize ();
    return 0;
}

【问题讨论】:

  • OLEDB OLE DB for the ODBC Programmer 的概述,其中涉及许多技术细节。
  • OLE DB Cursors (SQL Server Compact 描述了 SQL Server Compact 4.0 中的不同游标类型,在 Base Table Cursor 的描述中有以下句子:使用“SELECT * FROM table”产生查询处理器游标,只进或可滚动,而不是基表游标。只有基表游标支持更新。 所以游标类型可能与问题有关。
  • Supported Data Types and Data Type Mappings 描述了 SQL Server 和 SQL Server CE 支持的数据类型以及如何映射到另一个。

标签: sql-server visual-c++ sql-server-ce oledb atl


【解决方案1】:

MSDN says 表示 DBSTATUS_E_SCHEMAVIOLATION 表示

数据值违反了该列的架构约束。

只需在该页面上搜索 DBSTATUS_E_SCHEMAVIOLATION。

这很奇怪,因为您对 Count 列的唯一约束是“not null”。

就个人而言,我从未将 OLE DB 与 SQL Server 精简版一起使用,也从未像您那样尝试更新行。我将所有的 T-SQL 代码放在存储过程中,并使用“call”或“exec”来调用它们。在存储过程中,我使用标准的 UPDATE 语句。

在您的情况下,您很可能对光标的类型是正确的。当您调用myTable.Open 来运行查询SELECT [IdNumber], [Count] from Table_1 where [IdNumber] = '0000000103' 时,您很可能得到一个只读游标。我不知道如何检查它,但在你的位置,我会尝试找到一种方法来确认光标是否可更新。

【讨论】:

  • 感谢另一个观点。我有一些阅读要做:)
猜你喜欢
  • 1970-01-01
  • 2016-10-11
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 2010-10-16
  • 1970-01-01
  • 2012-10-30
相关资源
最近更新 更多