[VBNET] CommandBuilder 並未能正確以主鍵值為限制條件

問題編號:SRT070329799162
這個問題比較誇張,我是 3/29 發出去的,直到 4/25 才收到答案,4/26 才電話討論,以歷年 CSS 接觸經驗,這篇是最久的一次~
 
結論
問題核心是 MDAC 附的 ODBC Driver 不支援取得資料表結構,所以根本不知道哪欄是主鍵值 (PK) ,所以會以最後一欄唯一索引鍵當成主鍵值,因為主鍵值也是唯一索引鍵,所以發生問題。
另明確說明文件錯誤:
所有更新和刪除陳述式在 WHERE 子句中都只包含 PrimaryKey 資料行。如果沒有定義 PrimaryKey,則將可搜尋的資料行包含在 WHERE 子句中。這相當於 OverwriteChangesUpdate | OverwriteChangesDelete。 
All update and delete statements include only PrimaryKey columns in the WHERE clause. If no PrimaryKey is defined, all searchable columns are included in the WHERE clause. This is equivalent to OverwriteChangesUpdate | OverwriteChangesDelete
 
此說明中關於 PK 值的說明,在使用 Jet ODBC Driver 時不適用,其他 ODBC Driver 則視該 Driver 支援狀況而定,例如 SQL Server 則支援 PK 。
 
改善方式
改用 OleDb 或調整資料庫結構。
其他補充
據稱,ADO.NET 2.0 加強了 CommandBuilder 邏輯,讓其變得更嚴謹,所以 ADO.NET 1.1 可執行的,在 ADO.NET 2.0 上不見得可執行。
 
原始問題及回應過程

標題:
CommandBuilder 並未能正確以主鍵值為限制條件
 
造成問題:
ADO.NET 1.1 / ADO.NET 2.0 有不同結果,無法處理有效的 DBNull 值。
 
重現步驟:
附件為單一可執行檔案及資料庫,可直接掛載於 Test 目錄下後 (建議),以 http://localhost/Test/ 測試。
並利用 Win2003 IIS 6.0 建立 ASP.NET 1.1 集區及 2.0 集區,分別進行測試。
建議可開設兩虛擬目錄指向同一檔案,例如 Test11 採用 ASP.NET 1.1 ,Test20 採用 ASP.NET 2.0 ,分別以 http://localhost/Test11/cmdbuilder.aspxhttp://localhost/Test20/cmdbuilder.aspx 測試執行。
 
說明:
1. 主要程式碼如下,完整程式碼請參考附件:

Sub SubMain()

     Response.Buffer = False

     Dim m_Conn As System.Data.Odbc.OdbcConnection = New System.Data.Odbc.OdbcConnection

     Dim m_Adapter As New System.Data.Odbc.OdbcDataAdapter

     Dim m_CBuilder As System.Data.Odbc.OdbcCommandBuilder

     Dim m_DataSet As New System.Data.DataSet

     Dim strPath As String = MapPath("two.mdb")

     m_Conn.ConnectionString = "Driver={Microsoft Access Driver (*.mdb)}; dbq=" & strPath & ";"

     m_Adapter.SelectCommand = New System.Data.Odbc.OdbcCommand("Select * From TestTable Where (SN=1)", m_Conn)

     m_Adapter.Fill(m_DataSet)

     Dim strID As String

     If IsDBNull(m_DataSet.Tables(0).Rows(0).Item("ID")) Then

          strID = "0"

     Else

          strID = m_DataSet.Tables(0).Rows(0).Item("ID")

     End If

     m_DataSet.Tables(0).Rows(0).Item("ID") = CStr(CDbl(strID) + 1)

     Response.Write(DebugUpdate(m_Adapter))

     m_CBuilder = New System.Data.Odbc.OdbcCommandBuilder(m_Adapter)

     m_Adapter.Update(m_DataSet)

End Sub

 

2. 版本抓取程式碼為:

<td align="right">目前.Net framework 版本:</td>

<td> <% =Environment.Version %>

 

3. 測試資料表格內容:

SN
ID
1

[Null]

 
欄位屬性:
SN: 主鍵值,長整數
ID: 字串,允許 Null ,索引,唯一值。
 
4. 以 ASP.NET 1.1 集區執行時:

 
5. 以 ASP.NET 2.0 集區執行時,則發生錯誤:
 
若 ID 已有值,例如 ID=’1′ 時,則可順利執行。
 
若加上限制條件要求 Where 條件只包含主鍵值,則主鍵值不會出現在 Where 條件內,而是 ID=? (ID 為唯一索引值):
m_CBuilder.ConflictOption = System.Data.ConflictOption.OverwriteChanges
 

 
6. 若修改資料庫令 ID 欄位屬性改為 可重複索引值,則均可正常執行,且上圖 Where 條件將為 SN=?
 

補充說明:
資料庫存放目錄應以檔案總管操作,允許寫入權限。
 
連絡資訊:
姓名:鄭子璉
電話:xxxxxxxxxx / xxxxxxxxx
技術支援服務合約編號:xxxxxxxxx
 

背景:
以下軟體皆為繁體中文版 (MSDN VST 版)
OS: Windows 2003 R2 SP2 + Windows Update (2007/3/9)
DB: Access 2003
開發工具: Visual Studio Team Suite 2005 8.0.50727.762 (SP.050727-7600)


From: Bon Sung
Sent: Wednesday, April 25, 2007 2:33 PM
To: 鄭子璉
Subject: 微軟回覆您的問題 20070425V1 – Question about ODBCCommandBuilder

鄭先生您好,
 

Sorry from the late response.  Below is the summary till now for your reference.

 

[Problem Description]

=================

You have created a Access DB, which has defined “SN” as the primary key and “ID”  as “Indexed(Yes, no duplicates)” key. We use OdbcCommandBuilder with overwirtechanges option, the update command generated as below:

UPDATE TestTable SET SN = ?, ID = ? WHERE ((ID = ?)),

Which we expected should be: UPDATE TestTable SET SN = ?, ID = ? WHERE ((SN = ?))

 

Check MSDN, and found below comment:

 

OverwriteChanges All update and delete statements include only PrimaryKey columns in the WHERE clause. If no PrimaryKey is defined, all searchable columns are included in the WHERE clause. This is equivalent to OverwriteChangesUpdate | OverwriteChangesDelete. But it’s not true when we use Access.

 

[Action Tacken and conclusion]

========================

1.      Fire RFC.

2.      The expected behaviour not supported in Access.

Below is extracted from developer’s response:

The basic problem is that the Jet ODBC driver doesn’t support the ODBC function that would conclusively tell us which index/column is the primary key. Thus, we have to fall back to a less-precise method using the unique indexes, and using that method, we can’t tell for sure which columns are really the key. So, we are attempting to do what the docs say, but in this case it’s not totally possible.

廣告
Categories: 更新與回報 | 發表留言

文章分頁導航

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

在WordPress.com寫網誌.

%d 位部落客按了讚: