我正在研究将一个小型且简单的 SQL Server 数据库迁移到 SQL Server CE,目前正在使用一个小型原型(prototype)来研究 SQL Server CE 的基本操作,并考虑以下操作:(1)以编程方式创建表,(2)插入新的记录,(3) 读取现有记录,以及 (4) 更新现有记录。
在使用 Accessor 和 Accessor 结构的绑定(bind)成员时,原型(prototype)在更新现有记录时遇到问题。 select 语句可以正常工作,返回行和数据。但是,当我使用 SetData()
时,我可以更新访问器绑定(bind)成员。更新行的方法,HRESULT
返回值为 DB_E_ERRORSOCCURRED
.然后我检查 DBSTATUS
变量,我可以看到 DBSTATUS_E_SCHEMAVIOLATION
的错误代码.
DBSTATUS_E_SCHEMAVIOLATION
是什么意思意思是我需要改变什么,以便 SetData()
作品?
如果我修改 OLEDB 中使用的 SQL 查询,而不是执行 SELECT
我改为执行 UPDATE
WHERE
选择的行UPDATE
的子句被正确修改。问题似乎出在 SetData()
上。功能和绑定(bind)逻辑。当我用 SQL Server Express 做同样的事情时,我没有看到错误。我在 SQL Server CE 3.5 和 SQL Server Mobile for Visual Studio 2005 中都看到了同样的错误。
在 Visual Studio 2005 IDE 的输出窗口中,我看到以下几行。其中两行标有 <<<<< ATLTRACE2
从 ATLTRACE2 宏输出以显示各个列的状态值。从我在互联网上可以找到的信息来看,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 = 8
和 DBSTATUS_E_SCHEMAVIOLATION = 11
. IdNumber 的状态为 DBSTATUS_E_UNAVAILABLE
因为我在执行 SetData()
之前将其设置为被忽略.原型(prototype)的源代码如下。它的作用是在 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;
}
最佳答案
微软 says那 DBSTATUS_E_SCHEMAVIOLATION 意味着
The data value violated the schema's constraint for the column.
只需在该页面上搜索 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'
您很可能得到一个只读游标。我不知道如何检查它,但在你的位置,我会尝试找到一种方法来确认光标是否可以更新。
关于sql-server - SQL Server CE 3.5 更新行错误 DB_E_ERRORSOCCURRED 列错误是 DBSTATUS_E_SCHEMAVIOLATION,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23459657/