C#利用SqlDataAdapte對DataTable進行批量數據操作,可以讓我們大大簡化操作數據的代碼量,我們幾乎不需要循環和不關心用戶到底是新增還是修改,更不用編寫新增和修改以及刪除的SQL語句,適配器都幫我們在後台進行了很好的處理.
如果您要通過 SQL Server 存儲過程使用 DataAdapter 來編輯或刪除數據,請確保不要在存儲過程定義中使用 SET NOCOUNT ON。這將使返回的受影響的行數為零,DataAdapter 會將其解釋為並發沖突。在許多情況下,以何種順序向數據源發送通過 DataSet 所做的更改是非常重要的。例如,如果更新了現有行的主鍵值,並且添加了以新主鍵值作為外鍵的新行,則務必要在處理插入之前處理更新。可以使用 DataTable 的 Select 方法來返回僅引用具有特定 RowState 的 DataRow 數組。然後可以將返回的 DataRow 數組傳遞給 DataAdapter 的 Update 方法來處理已修改的行。通過指定要更新的行的子集,可以控制處理插入、更新和刪除的順序。以下代碼確保首先處理表中已刪除的行,然後處理已更新的行,然後處理已插入的行。
1 DataTable table = dataSet.Tables["Customers"]; 2 //第一步處理刪除. 3 adapter.Update(table.Select(null, null, DataViewRowState.Deleted)); 4 //接著處理更新 5 adapter.Update(table.Select(null, null, 6 DataViewRowState.ModifiedCurrent)); 7 //最後處理新增 8 adapter.Update(table.Select(null, null, DataViewRowState.Added));
注意 對 DataSet、DataTable 或 DataRow 調用 AcceptChanges 將導致 DataRow 的所有 Original 值被 DataRow 的 Current 值覆蓋。如果修改了唯一標識該行的字段值,則在調用 AcceptChanges 後,Original 值將不再匹配數據源中的值。在調用 DataAdapter 的 Update 方法期間會對每一行自動調用 AcceptChanges。在調用 Update 方法期間,通過先將 DataAdapter 的 AcceptChangesDuringUpdate 屬性設置為 false,或為 RowUpdated 事件創建一個事件處理程序並將 Status 設置為 SkipCurrentRow,可以保留原始值。(來自MSDN)
數據庫的表設計好後,可以用VS連接數據庫,並將myUser 表拖放到數據集設計器中(重命名為dsUser),默認情況下,數據集會自動生成Fill方法,我們這裡需要手動進行刪除,只保留表結構即可,數據查詢和操作邏輯我們進行自定義.如下圖所示:
新建一個窗體,編譯後可以從工具欄將上一步新建的dsUser強類型數據集拖放到窗體上,另外添加一個BindingSource控件(主要用於對DataGridView中的數據庫和DataSet的數據進行綁定)
BindingSource中選擇數據源DataSource為dsUser,然後選擇數據集中的一個表myUser進行綁定:
設置DataGridView的數據源為bindingSource,這樣通過bindingSource1就實現了DataGridView和dsUser的數據綁定,也就是說在界面DataGridView上進行操作,可以同步到dsUser中(會在每行上打上標志)
可以利用SqlDataAdapter批量更新DataTable中的數據庫,也支持表格中同時進行了刪除/修改和新增的操作,下面的代碼中,用select * from {0} where 1=2查詢語句為SqlDataAdapter提供架構:
//生成架構 string selectSQL = string.Format("select * from {0} where 1=2", dt.TableName); SqlDataAdapter sda = new SqlDataAdapter(selectSQL, ConnectionString)
而後用SqlCommandBuilder自動構建新增/刪除/修改的命令,這樣就可以用sda.Update()方法對數據表進行批量操作了:
1 SqlCommandBuilder scb = new SqlCommandBuilder(sda); 2 sda.Update(dt);
完整代碼如下:
1 public static void UpdateDataSet(DataSet ds, string tableName) 2 { 3 try 4 { 5 if (tableName == "") 6 { 7 throw new ArgumentNullException("tableName 不能為空"); 8 } 9 //生成架構 10 string selectSQL = string.Format("select * from {0} where 1=2", tableName); 11 using (SqlDataAdapter sda = new SqlDataAdapter(selectSQL, ConnectionString)) 12 { 13 14 SqlCommandBuilder scb = new SqlCommandBuilder(sda); 15 16 sda.UpdateCommand = scb.GetUpdateCommand(); 17 sda.InsertCommand = scb.GetInsertCommand(); 18 sda.DeleteCommand = scb.GetDeleteCommand(); 19 20 sda.Update(ds, tableName); 21 ds.Tables[tableName].AcceptChanges(); 22 DisposeCommand(sda.UpdateCommand); 23 DisposeCommand(sda.InsertCommand); 24 DisposeCommand(sda.DeleteCommand); 25 sda.Dispose(); 26 scb.Dispose(); 27 } 28 } 29 catch (SqlException e) 30 { 31 throw e; 32 } 33 } View Code為了確保在用戶編輯完成後,立刻將數據同步到數據集中,必須調用bindingSource的EndEdit方法來同步數據.
1 private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) 2 { 3 this.bindingSource.EndEdit(); 4 }
在窗體加載時,調用刷新方法,然後程序會自動將數據綁定到DataGridView上:
1 private bool fnRefresh() 2 { 3 string sql = string.Format("select * from myUser"); 4 CM.Products.DataAccess.SqlHelper.GetDataTableBySQL(this.dsUser.myUser, sql); 5 return true; 6 }
我們可以通過DataGridView的EndEdit方法來獲取當前用戶是否已經結束編輯:
1 bool isEnd= this.dataGridView1.EndEdit();
另外可以通過GetChanges()方法來獲取修改的數據,返回一個DataTable.
1 DataTable dtModify = this.dsUser.myUser.GetChanges(DataRowState.Modified);
調用UpdateTable方法,即可對表格進行批量處理(這裡就一個表,如果是多個表,那麼需要指明表名):
1 private bool Save() 2 { 3 try 4 { 5 DataAccess.SqlHelper.UpdateDataSet(this.dsUser, "myUser"); 6 this.dsUser.myUser.AcceptChanges();//提交數據庫 7 return true; 8 } 9 catch (Exception ex) 10 { 11 return false; 12 } 13 14 }
當用戶選擇一個單元格時,會獲取到當前行的索引,然後調用RemoveAt()方法進行刪除,由於用bindingSource進行了綁定,可以直接調用save()方法進行數據保存:
1 private void bindingNavigatorDeleteItem_Click(object sender, EventArgs e) 2 { 3 if (this.dataGridView1.CurrentRow != null) 4 { 5 int index = this.dataGridView1.CurrentRow.Index; 6 if (index > -1) 7 { 8 this.dataGridView1.Rows.RemoveAt(index); 9 Save(); 10 } 11 } 12 }
當用戶單擊新增按鈕時,我們創建一個強類型的myUserRow,然後給它附上默認值(特別是主鍵)
1 //add row 2 private void toolStripButton1_Click(object sender, EventArgs e) 3 { 4 Common.dsUser.myUserRow dr = this.dsUser.myUser.NewmyUserRow(); 5 dr["ID"] = System.Guid.NewGuid().ToString(); 6 dr["Name"] = "Name"; 7 dr["AddTime"] = DateTime.Now.ToString(); 8 9 this.dsUser.myUser.AddmyUserRow(dr); 10 }