C#中dataGrid的批量更新問題解決方案

更新數據集
首先需要說明的是我這裏去掉了Order Details表,對兩個表的操作只是其中的幾個字段。下面是窗體界面:


單選框用來選擇不同的更新方法。
在DataAccess類中增加兩個類成員變量:
     private SqlDataAdapter _customerDataAdapter; //客戶數據適配器
     private SqlDataAdapter _orderDataAdapter; //訂單數據適配器
 
customerDataAdapter在構造函數中的初始化爲
//實例化_customerDataAdapter
SqlCommand selectCustomerComm = new SqlCommand("GetCustomer",_conn);
selectCustomerComm.CommandType = CommandType.StoredProcedure;
selectCustomerComm.Parameters.Add("@CustomerID",SqlDbType.NChar,5,"CustomerID");
        
SqlCommand insertCustomerComm = new SqlCommand("AddCustomer",_conn);
insertCustomerComm.CommandType = CommandType.StoredProcedure;
insertCustomerComm.Parameters.Add("@CustomerID",SqlDbType.NChar,5,"CustomerID");
insertCustomerComm.Parameters.Add("@CompanyName",SqlDbType.NVarChar,40,"CompanyName");
insertCustomerComm.Parameters.Add("@ContactName",SqlDbType.NVarChar,30,"ContactName");
 
SqlCommand updateCustomerComm = new SqlCommand("UpdateCustomer",_conn);
updateCustomerComm.CommandType = CommandType.StoredProcedure;
updateCustomerComm.Parameters.Add("@CustomerID",SqlDbType.NChar,5,"CustomerID");
updateCustomerComm.Parameters.Add("@CompanyName",SqlDbType.NVarChar,40,"CompanyName");
updateCustomerComm.Parameters.Add("@ContactName",SqlDbType.NVarChar,30,"ContactName");
             
SqlCommand deleteCustomerComm = new SqlCommand("DeleteCustomer",_conn);
deleteCustomerComm.CommandType = CommandType.StoredProcedure;
deleteCustomerComm.Parameters.Add("@CustomerID",SqlDbType.NChar,5,"CustomerID");
 
_customerDataAdapter = new SqlDataAdapter(selectCustomerComm);
_customerDataAdapter.InsertCommand = insertCustomerComm;
_customerDataAdapter.UpdateCommand = updateCustomerComm;
_customerDataAdapter.DeleteCommand = deleteCustomerComm;
 
上面的代碼完全可以用設計器生成,覺得有些東西自己寫感覺更好,不過代碼還是很多。
對於_orderDataAdapter的初始化同上面的差不多,這裏我們只看訂單增加的處理,下面是存儲過程:
CREATE PROCEDURE AddOrder
(
     @OrderID INT OUT,
     @CustomerID NCHAR(5),
     @OrderDate DATETIME
)
AS
INSERT INTO Orders
(
     CustomerID ,
     OrderDate
)
VALUES
(
     @CustomerID ,
     @OrderDate
)
--SELECT @OrderID = @@IDENTITY //使用觸發器有可能出現問題
SET @OrderID = SCOPE_IDENTITY()
GO
 
OrderID自動增長值的獲取通過輸出參數來完成,這個相當不錯,如果使用SqlDataAdapter.RowUpdated事件來處理那效率會很低。
對insertOrderComm對象的定義爲:
SqlCommand insertOrderComm = new SqlCommand("AddOrder",_conn);
insertOrderComm.CommandType = CommandType.StoredProcedure;
insertOrderComm.Parameters.Add("@OrderID",SqlDbType.Int,4,"OrderID");
insertOrderComm.Parameters["@OrderID"].Direction = ParameterDirection.Output;
insertOrderComm.Parameters.Add("@OrderDate",SqlDbType.DateTime,8,"OrderDate");
insertOrderComm.Parameters.Add("@CustomerID",SqlDbType.NChar,5,"CustomerID");
 
在實現數據的更新方法之前我們先來明確一些更新邏輯:
對於標記爲刪除的行,先刪除訂單表的數據,再刪除客戶表的數據;
對於標記爲添加的行,先添加客戶表的數據,再添加訂單表的數據。
 
(1)實現用獲取修改過的DataSet的副本子集來更新數據的方法。
這也是調用Xml Web Service更新數據的常用方法,先來看第一個版本,子集的獲取通過DataSet.GetChangs方法來完成。
//使用數據集子集更新數據
public void UpdateCustomerOrders(DatasetOrders ds)
{            
     DataSet dsModified = ds.GetChanges(DataRowState.Modified);//獲取修改過的行
     DataSet dsDeleted = ds.GetChanges(DataRowState.Deleted);//獲取標記爲刪除的行
     DataSet dsAdded = ds.GetChanges(DataRowState.Added);//獲取增加的行
     try
     {   
         _conn.Open();//先添加客戶表數據,再添加訂單表數據
         if(dsAdded != null)
         {
              _customerDataAdapter.Update(dsAdded,"Customers");
              _orderDataAdapter.Update(dsAdded,"Orders");
              ds.Merge(dsAdded);
         }
         if(dsModified != null)//更新數據表
         {
              _customerDataAdapter.Update(dsModified,"Customers");
              _orderDataAdapter.Update(dsModified,"Orders");
              ds.Merge(dsModified);
         }
         if(dsDeleted != null)//先刪除訂單表數據,再刪除客戶表數據
         {
              _orderDataAdapter.Update(dsDeleted,"Orders");
              _customerDataAdapter.Update(dsDeleted,"Customers");
              ds.Merge(dsDeleted);
         }                 
     }
     catch(Exception ex)
     {
         throw new Exception("更新數據出錯",ex);
     }
     finally
     {
         if(_conn.State != ConnectionState.Closed)
              _conn.Close();
     }
}
上面的方法看上去比較清晰,不過效率不會很高,至少中間創建了三個DataSet,然後又進行了多次合併。
(2)另一方法就是引用更新,不創建副本。
相對來說性能會高許多,但是如果用在Web服務上傳輸的數據量會更大(可以結合兩個方法進行改進)。具體的實現就是通過DataTable.Select方法選擇行狀態來實現。
//引用方式更新數據
public void UpdateCustomerOrders(DataSet ds)
{
     try
     {   
         _conn.Open();
         //先添加客戶表數據,再添加訂單表數據      _customerDataAdapter.Update(ds.Tables["Customers"].Select("","",DataViewRowState.Added));
     _orderDataAdapter.Update(ds.Tables["Orders"].Select("","",DataViewRowState.Added));
     //更新數據表
     _customerDataAdapter.Update(ds.Tables["Customers"].Select("","",DataViewRowState.ModifiedCurrent));
     _orderDataAdapter.Update(ds.Tables["Orders"].Select("","",DataViewRowState.ModifiedCurrent));
//先刪除訂單表數據,再刪除客戶表數據
     _orderDataAdapter.Update(ds.Tables["Orders"].Select("","",DataViewRowState.Deleted));
     _customerDataAdapter.Update(ds.Tables["Customers"].Select("","",DataViewRowState.Deleted));           
     }
     catch(Exception ex)
     {
         throw new Exception("更新數據出錯",ex);
     }
     finally
     {
         if(_conn.State != ConnectionState.Closed)
              _conn.Close();
     }
}
結合上面的兩個方法我們可想到調用Web Service有更合理的方法來完成。
(3)使用事務
public void UpdateCustomerOrdersWithTransaction(DataSet ds)
{
     SqlTransaction trans = null;
     try
     {   
         _conn.Open();
         trans = _conn.BeginTransaction();
         _customerDataAdapter.DeleteCommand.Transaction = trans;
         _customerDataAdapter.InsertCommand.Transaction = trans;
         _customerDataAdapter.UpdateCommand.Transaction = trans;
         _orderDataAdapter.DeleteCommand.Transaction = trans;
         _orderDataAdapter.InsertCommand.Transaction = trans;
         _orderDataAdapter.UpdateCommand.Transaction = trans;
     _customerDataAdapter.Update(ds.Tables["Customers"].Select("","",DataViewRowState.Added));
                   _orderDataAdapter.Update(ds.Tables["Orders"].Select("","",DataViewRowState.Added));
     _customerDataAdapter.Update(ds.Tables["Customers"].Select("","",DataViewRowState.ModifiedCurrent));
     _orderDataAdapter.Update(ds.Tables["Orders"].Select("","",DataViewRowState.ModifiedCurrent));
     _orderDataAdapter.Update(ds.Tables["Orders"].Select("","",DataViewRowState.Deleted));
     _customerDataAdapter.Update(ds.Tables["Customers"].Select("","",DataViewRowState.Deleted)); 
          trans.Commit();
     }
     catch(Exception ex)
     {
         trans.Rollback();
         throw new Exception("更新數據出錯",ex);
     }
     finally
     {
         if(_conn.State != ConnectionState.Closed)
              _conn.Close();
     }
}
最後讓我們來看看窗體的按鈕更新事件的代碼:
private void buttonUpdate_Click(object sender, System.EventArgs e)
{
              //提交編輯數據
     this.BindingContext[this._ds].EndCurrentEdit();
    
     if(radioButtonRef.Checked == true)//引用方式更新
         _dataAccess.UpdateCustomerOrders((DataSet)_ds);
     else if(radioButtonTrans.Checked == true)//啓用事務更新數據表
         _dataAccess.UpdateCustomerOrdersWithTransaction((DataSet)_ds);
     else
     {
         DatasetOrders changedData = (DatasetOrders)_ds.GetChanges();
         if(radioButtonWeb.Checked == true)//Web服務的更正更新
         {                     
              _dataAccess.UpdateCustomerOrders((DataSet)changedData);
         }
         else//創建副本合併方式更新
         {                 
              _dataAccess.UpdateCustomerOrders(changedData);
         }
         //去除訂單表中添加的虛擬行
         foreach(DataRow row in _ds.Orders.Select("","",DataViewRowState.Added))
              _ds.Orders.RemoveOrdersRow((DatasetOrders.OrdersRow)row);
         //去除客戶表中添加的虛擬行
         foreach(DataRow row in _ds.Customers.Select("","",DataViewRowState.Added))
              _ds.Customers.RemoveCustomersRow((DatasetOrders.CustomersRow)row);
         _ds.Merge(changedData);
     }
     //提交數據集狀態
     _ds.AcceptChanges();
}
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章