VB.net从ADODB迁移到ADO.NET时新增DataTable行后更新数据库报错
问题原因及修复方案
核心错误原因
Access保留字冲突
你表中的Count字段是Access(Jet/ACE引擎)的SQL保留关键字,OleDbCommandBuilder自动生成SQL语句时默认不会给标识符加转义符号,生成的INSERT/UPDATE语句直接使用未转义的Count作为字段名,触发语法错误。
额外说明:你看到的SQL语句里的?是OleDb的标准位置参数占位符,属于正常设计,DataAdapter会自动把DataRow的字段值绑定到对应参数,不是引发错误的原因。业务逻辑与原ADODB逻辑不一致
原ADODB代码逻辑为:查询到匹配记录则直接修改现有记录的Count字段+1,无匹配记录才新增行。但你的新代码不管是否查询到匹配记录,都会新建一行插入到表中,且如果查询到匹配记录时,新建的行除了Count字段外其余字段均未赋值,也会引发数据异常。CommandBuilder配置缺失
你只手动给DataAdapter赋值了UpdateCommand,没有处理InsertCommand,且未配置标识符转义规则。
修复步骤
- 给CommandBuilder配置标识符转义
初始化OleDbCommandBuilder之后添加两行配置,让生成的SQL自动给字段名加方括号转义:
Dim dtBuilder As New OleDbCommandBuilder(daX) ' 新增以下两行,适配Access的标识符转义规则 dtBuilder.QuotePrefix = "[" dtBuilder.QuoteSuffix = "]" ' 不需要手动赋值UpdateCommand,CommandBuilder会自动生成所有增删改命令
- 修正业务逻辑
把新建行、赋值的逻辑改成和原ADODB一致:
Dim r As DataRow If dtUni.Rows.Count = 0 Then ' 无匹配记录,新建行 r = dtUni.NewRow() r("Species") = sSpecies r("ProdDesc") = sNewProd r("StdUnits") = sgUnits r("Footage") = 0 If sgUnits = 0 Then r("PieceCnt") = 0 ElseIf iStdPcs > 0 Then r("StdPieceCnt") = iStdPcs r("StdFootage") = 0 r("PieceCnt") = iPcs ElseIf iStdFtg > 0 Then r("StdFootage") = iStdFtg r("StdPieceCnt") = 0 r("PieceCnt") = 0 End If If bLgths = True Then r("Length") = sLength r("MultiLgth") = sMultiLgth Else r("Length") = "" ' 和原ADODB逻辑保持一致,赋值空字符串而非"0" r("MultiLgth") = "" End If dtUni.Rows.Add(r) Else ' 有匹配记录,取第一条现有记录修改Count r = dtUni.Rows(0) End If ' 统一处理Count字段 If IsDBNull(r("Count")) Then r("Count") = 0 Else r("Count") += 1 End If
- 简化Update调用
不需要绕到DataSet,直接更新DataTable即可,避免DataSet同步问题:
Try daX.Update(dtUni) Catch ex As Exception MsgBox(ex.Message) End Try
内容的提问来源于stack exchange,提问作者CircleDot
相关产品推荐
相关产品推荐

