使用您的任何 Select 方法填充任何 TableAdapter





4.00/5 (5投票s)
避免惱人的表適配器加載錯誤,無法啟用約束。
引言
在這裡,我們將看到如何填充任何 TableAdapter
DataTable
並避免可怕的問題
Server Error in '/REDB' Application.
Failed to enable constraints. One or more rows contain values
violating non-null, unique, or foreign-key constraints.
背景
首先,讓我們概述一下 TableAdapter
。您知道它是什麼以及如何使用它,否則您甚至不會在這裡。
- 我們知道
TableAdapter
不是 .NET framework 對象。(它是一個 VS Designer 創建的對象,因此請勿嘗試瀏覽TableAdapter
.NET 對象。) - 繼承自
System.ComponentModel.Component
,**而不是**DataAdapter
。 - 封裝了一個
DataAdapter
,例如SQLDataAdapter
等。 - 封裝了一個
SQLConnection
。 - 封裝了一個 SQL
CommandCollection
。
private global::System.Data.SqlClient.SqlDataAdapter _adapter;
private global::System.Data.SqlClient.SqlConnection _connection;
private global::System.Data.SqlClient.SqlCommand[] _commandCollection;
使用代码
創建一個 Web 項目。為其命名。保存它。創建一個引用古老的 Northwind 資料庫的 DataSet
。允許將 DataSet
保存在 App_Code 文件夾中。
使用 Products 表創建一個 ProductsTableAdapter
。讓我們使用一個名為 ProductsTableAdapter
的示例 TableAdapter
,它屬於我們已經創建的古老的 NorthwindDataSet
。(請立即創建它,我會等。)
創建您自定義的 Get
和 Fill
方法。將一個命名為 GetProductNames
,另一個命名為 FillProductNames
。
當您嘗試調用在 ProductsTableAdapter
中創建的自定義 Fill
方法之一,而該方法不包含默認 Select
方法的 DataTable
中的所有 DataColumn
時,您將遇到這個有趣的對話框警告消息
直到您嘗試調用僅返回產品名稱列表的自定義 GetProductNames()
方法,此警告才變得有意義。
當您使用 Sir Wizard 提供的配置和預覽調用此方法時,一切看起來都很棒。所有產品 DataTable
列都顯示為空,除了產品名稱。太棒了!這正是我們想要的。(實際上,我認為大多數人都期望得到一個產品名稱列表,而沒有其他數據列。)
好吧,我們可以暫時接受它。讓我們填入數據,以便至少可以使用產品名稱列表。
大多數人會這樣做
NorthwindDataSetTableAdapters.ProductsTableAdapter Adaptr =
new ProductsTableAdapter();
NorthwindDataSet.ProductsDataTable tbl =
new NorthwindDataSet.ProductsDataTable();
為了確保萬無一失,我們清除任何可能阻止我們的表填充的表約束。
tbl.Constraints.Clear();
現在,我們調用填充方法
tbl=Adaptr.GetProductNames();
//FILL the table and herein lies the problem.
可怕的錯誤
Server Error in '/REDB' Application.
Failed to enable constraints. One or more rows contain values
violating non-null, unique, or foreign-key constraints.
究竟發生了什麼?我們知道它在「預覽數據」中起作用。(您會在聽到我說出顯而易見的事實時尖叫,但首先,簡要分析一下。)
我們是否用 GetProductNames()
調用返回的對象覆蓋了我們的 tbl
對象?沒有,因為該調用在 Fill
方法調用中失敗了。讓我們檢查一下調用堆棧。
Line 9506: this.Adapter.SelectCommand = this.CommandCollection[1];
Line 9507: NorthwindDataSet.ProductsDataTable dataTable =
new NorthwindDataSet.ProductsDataTable();
Line 9508: this.Adapter.Fill(dataTable);
Line 9509: return dataTable;
Line 9510:
我們從未到達返回對象。
另外,請注意 CommandCollection
調用了其集合中的第二個項目(稍後會有更多關於該內容的相關信息)。
我們的 tbl
對象之前被創建為一個新的 ProductsDataTable
。我這樣做是有意的。通常,我們會聲明一個新對象並在一行代碼中將其賦值
ProductsDataTable tbl = Adaptr.GetProductNames();
VB
Dim tbl AS ProductsDataTable = Adaptr.GetProductNames()
無論哪種情況,調用都會失敗。
由於我們的 tbl
對象已實例化為一個新的 ProductsDataTable
(這是我們開始處理它的唯一方法),讓我們修復最明顯的問題
columns = tbl.Columns; //Get reference to the Columns Collection
foreach (DataColumn dc in columns) {dc.AllowDBNull = true;}
這是您需要做的唯一一件事,因為我們現在將把我們的 tbl
對象傳遞給 **fill** a DataTable
方法,而不是 **get** a DataTable
方法。(我警告過您會討厭它的簡單性。)
Adaptr.FillProductNames(tbl); //No Errors. Yes!
Console.Write("Row Count is " tbl.Rows.Count.ToString());
Response.Write("Row Count is " tbl.Rows.Count.ToString());
可以在 CodeProject 上找到一篇關於 TableAdapter
動態 SQL 的優秀文章。
关注点
tbl.Constraints.Clear()
並不是解決問題的方法。AllowDBNull
在所有情況下才是真正的解決方案。我花了一些時間才意識到,我幾乎總是返回一個 DataTable
,並且從未嘗試將一個 DataTable
傳遞以進行填充。那時我才意識到 **fill** DataTable
自定義方法的用處。
您始終可以嘗試更改架構或創建單獨的 TableAdapter
以生成與您的數據一致的架構,但何必呢?這種方法非常有效。
您創建的第一個 Select 查詢是所有其他查詢的架構基礎。它成為默認查詢,並且其方法被 DataObjectMethodAttribute
裝飾,並且 Select
被設置為 true
。現在,所有其他查詢都必須使用此默認架構。這就是為什麼您會看到上面顯示的警告對話框。
注意 SQL 旁邊的複選標記。這是 TableAdapter
中的第一個也是默認的 Select 查詢。第二個查詢成為 CommandCollection[1]
,依此類推。
謝謝,您們真是太棒的聽眾。
RickIsWright - www.rickiswright.com。
历史
- 發布日期:2009 年 5 月 11 日。