小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

DataBase和DataSet同步數據

 悟靜 2012-06-14

DataBase和DataSet同步數據
數據適配器概述
l         DataAdapter 連接到數據庫以填充DataSet 的對象。然后,它又連接回數據庫,根據DataSet 保留數據時所執(zhí)行的操作來更新數據庫中的該數據。

l         DataAdapter:它起著橋梁的作用,在DataSet 和其源數據存儲區(qū)之間進行數據檢索和保存.

l         DataAdapter對象可以隱藏和Connection、Command對象溝通的細節(jié),通過DataAdapter對象建立、初始化DataTable,從而和DataSet對象結合起來在內存存放數據表副本,實現離線式數據庫操作.

數據適配器的屬性
l         數據源更新

– InsertCommand

– SelectCommand

– DeleteCommand

– UpdateCommand

l         TableMappings:用于維持數據集中的列和數據源中列的關系

l         AcceptChangesDuringFill:決定AccepChnages方法是否被添加到數據集中的每一行所調用,默認為true

TableMappings集合
l         數據集和數據源的橋梁:

– 數據集并不清除它所包含的數據從哪里來,而Connection也不知道它所檢索的數據都發(fā)生了什么改變。

– 數據適配器用于維持這兩者之間的聯系,它通過TableMappings集合來實現這一目標。

l         包括

– DataTableMappings

– DataColumnMappings

1.         SourceColumn

2.         DataSetColumn

 

 

 

[參考代碼]

protected  System.Web.UI.WebControls.DropDownList  ddlClassCode;

//省略

SqlDataAdapter da = new SqlDataAdapter("select Distinct classCode from tbClassInfo",con);

DataSet ds = new DataSet("myDs");

da.Fill(ds,"Class");

ddlClassCode.DataTextField = "ClassCode";

ddlClassCode.DataSource = ds.Tables["Class"].DefaultView;

ddlClassCode.DataBind();

 

ddlClassCode.SelectedIndex = nIndex;

string strSelectedClass = ddlClassCode.SelectedItem.Text;

string strSql = "select * from tbStudentInfo where StudentID in (select studentid from tbClassInfo where classcode='"+strSelectedClass+"')";

da.SelectCommand.CommandText =strSql;

//映射

da.TableMappings.Add("tbStudentInfo","Student");

da.TableMappings[0].ColumnMappings.Add("StudentID","學生ID");

da.TableMappings[0].ColumnMappings.Add("StudentName","學生姓名");

da.TableMappings[0].ColumnMappings.Add("StudentPass","密碼");

da.TableMappings[0].ColumnMappings.Add("Sex","性別");

da.TableMappings[0].ColumnMappings.Add("BirthDay","生日");

da.TableMappings[0].ColumnMappings.Add("Email","郵件地址");

da.TableMappings[0].ColumnMappings.Add("Score","成績");

這樣在DataSource中的列名就被映射為后者。

DataSet版本
DataSet中,可以存在同一個DataRow的多個版本。它們由DataRowWVersion枚舉來指定。

– Current該行中包含當前值。

– Default根據當前DataRowState,為默認行版本。

– Original該行中包含其原始值。

– Proposed該行中包含建議值。

DataRowVersion
版本在以下情況下發(fā)生更改:

在調用DataRow 對象的BeginEdit 方法之后,如果更改該值,則Current 和Proposed 值變得可用。

在調用DataRow 對象的CancelEdit 方法之后,Proposed 值將被刪除。

在調用DataRow 對象的EndEdit 方法之后,Proposed值變成Current 值。

在調用DataRow 對象的AcceptChanges 方法之后,Original 值變得與Current 值相同。

在調用DataTable 對象的AcceptChanges 方法之后,Original 值變得與Current 值相同。

在調用DataRow 對象的RejectChanges 之后,Proposed 值將被丟棄,版本變成Current。

 

如果對 DataSet、DataTable 或 DataRow 調用 AcceptChanges,則將使 DataRow 的所有 Original 值都將被重寫為該 DataRow 的 Current 值。如果已修改將該行標識為唯一行的字段值,那么當調用 AcceptChanges 后,Original 值將不再匹配數據源中的值。

Fill方法的使用
默認情況下,在使用DataAdapter的Fill方法時,除了會填充DataSet之外,還會自動調用DataSet.AcceptChanges。調用后所有行狀態(tài)中沒有任何行是“新改變的”。

對于某些情況,如希望從多個數據源填充一個DataSet,再將其寫回另外一個數據存儲,這時要把DataAdapter的屬性AcceptChangesDuringFill設置為false,以便讓結果行表現為新添加的行。

 

[參考代碼]

//將指定的行Fill到SqlDataAdapter中

//0表示要Fill的行標 1表示要Fill的行數

da.Fill(ds,0,1,"AuthorAndTitle");

Update方法
當調用Update 方法時,DataAdapter 將分析已作出的更改并執(zhí)行相應的命令(INSERT、UPDATE 或DELETE)。當DataAdapter 遇到對DataRow 的更改時,它將使用InsertCommand、UpdateCommand 或DeleteCommand 來處理該更改。這樣,您就可以通過在設計時指定命令語法并在可能時通過使用存儲過程來盡量提高ADO.NET 應用程序的性能。

在調用Update 之前,必須顯式設置這些命令。如果調用了Update 但不存在用于特定更新的相應命令(例如,不存在用于已刪除行的DeleteCommand),則將引發(fā)異常。

[參考代碼]

SqlDataAdapter catDA = new SqlDataAdapter("SELECT * FROM Categories", nwindConn);      

catDA.UpdateCommand = new SqlCommand("UPDATE Categories SET CategoryName = @CategoryName " +"WHERE CategoryID = @CategoryID" , nwindConn);

catDA.UpdateCommand.Parameters.Add("@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");

SqlParameter workParm = catDA.UpdateCommand.Parameters.Add("@CategoryID", SqlDbType.Int);

workParm.SourceColumn = "CategoryID";

//如果下面的不一致,說明數據庫已經更新了

workParm.SourceVersion = DataRowVersion.Original;

DataSet catDS = new DataSet();

catDA.Fill(catDS, "Categories");  

DataRow cRow = catDS.Tables["Categories"].Rows[0];

cRow["CategoryName"] = "NewName";

catDA.Update(catDS,"Categories");

 

MSDN上面的解釋:

1.       當調用 Update 方法時,DataAdapter 將分析已作出的更改并執(zhí)行相應的命令(INSERT、UPDATE 或 DELETE)。當 DataAdapter 遇到對 DataRow 的更改時,它將使用 InsertCommand、UpdateCommand 或 DeleteCommand 來處理該更改。這樣,您就可以通過在設計時指定命令語法并在可能時通過使用存儲過程來盡量提高 ADO.NET 應用程序的性能。在調用 Update 之前,必須顯式設置這些命令。如果調用了 Update 但不存在用于特定更新的相應命令(例如,不存在用于已刪除行的 DeleteCommand),則將引發(fā)異常。

2.        請注意,在 UPDATE 語句的 WHERE 子句中指定的參數設置為使用 SourceColumn 的 Original 值。這一點很重要,因為 Current 值可能已被修改,并且可能不匹配數據源中的值。Original 值是曾用來從數據源填充 DataTable 的值。

3.        如果 SelectCommand 返回 OUTER JOIN 的結果,則 DataAdapter 不會為生成的 DataTable 設置 PrimaryKey 值。您必須自己定義 PrimaryKey 以確保正確解析重復行

CommandBuilder
如果DataTable 映射到單個數據庫表或從單個數據庫表生成,則可以利用CommandBuilder 對象自動生成DataAdapter 的DeleteCommand、InsertCommand 和UpdateCommand。

       滿足以下條件,就可以使用CommandBuilder自動生成命令

(1)       DataTable 映射到單個數據庫表或從單個數據庫表生成

(2)       必須使用了SelectCommand命令了,并有主建

為了生成INSERT、UPDATE 或DELETE語句,CommandBuilder 會自動使用SelectCommand 屬性來檢索所需的元數據集。

 

[參考代碼]

SqlDataAdapter catDA = new SqlDataAdapter("SELECT * FROM Categories", nwindConn);      

catDA.InsertCommand = new SqlCommand("Insert into Categories(CategoryName,Description) values"+" (@CategoryName,@Description)", nwindConn);

catDA.InsertCommand.Parameters.Add("@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");

catDA.InsertCommand.Parameters.Add("@Description", SqlDbType.NText, 16, "Description");

DataSet catDS = new DataSet();

catDA.Fill(catDS, "Categories");  

 

DataRow dr = catDS.Tables["Categories"].NewRow();

dr["CategoryName"] = "Added New Name";

dr["Description"] = "my Description";

catDS.Tables["Categories"].Rows.Add(dr);

 

catDA.Update(catDS,"Categories");

數據適配器的事件
OnRowUpdating:在數據行更新前執(zhí)行

OnRowUpdated:在數據行更新后執(zhí)行。其最佳用法是檢查單條更新語句的執(zhí)行結果。

 

SqlRowUpdatedEventArgs屬性

屬性
 描述
 
Command
 要執(zhí)行的數據命令
 
Errors
 錯誤
 
Row
 要更新的行
 
StatementType
 要執(zhí)行的命令類型,可能為Select、Insert、Delete和Update
 
RecordsAffected
 要影響的行數
 
TableMapping
 更新所使用的DataTableMapping
 

 

[參考代碼]

myDataAdapter.RowUpdating += new SqlRowUpdatingEventHandler(MyUpdatingHandler);

//省略,OnRowUpdating主要用于在更新前判斷數據源是否已經被其他客戶端更改

public void MyUpdatingHandler(object adapter,SqlRowUpdatingEventArgs e)

{

       switch(e.StatementType)

       {

              case StatementType.Update:

              {

                     SqlConnection myConnection = new SqlConnection( "server=(local);uid=sa;pwd=111;database=Pubs" );

                     string strSql = "Select * From Authors where au_fname='"

                                          +e.Row["au_fname",DataRowVersion.Original]+"'";

                     SqlCommand com = new SqlCommand(strSql,myConnection);

                     myConnection.Open();

                     if(com.ExecuteNonQuery()==0)

                     {

                            Response.Write("出錯!有用戶已經修改過數據集!");

                            e.Status = UpdateStatus.ErrorsOccurred;//報錯

                     }

                     myConnection.Close();

                     break;

              }

       }

}

myDataAdapter.RowUpdated += new SqlRowUpdatedEventHandler(MyUpdatedHandler);

//省略,OnRowUpdated主要用于更新出錯時,是否忽略錯誤繼續(xù)更新

public void MyUpdatedHandler(object adapter,SqlRowUpdatedEventArgs e)

{

switch(e.StatementType)

       {

       case StatementType.Update:

              if(e.Status==UpdateStatus.ErrorsOccurred)

              {

                                   e.Status = UpdateStatus.SkipCurrentRow;

                                   break;

                     }

              }

}

使用數據適配器最佳實踐
使用多個表填充一個DataSet
如果你是用批處理從多個表返回數據并把這些數據填充到一個DataSet,fill方法將會使用第一個表的表名命名第一個表,以后的表命名將會采用在第一個表的表名基礎上加上一個遞增的數字。

SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Customers;SELECT * FROM Orders;", myConnection);

da.TableMappings.Add("Customers1", "Orders");

DataSet ds = new DataSet();

da.Fill(ds, "Customers");

避免自動增量值沖突
DataSet 使您可標識那些添加新行時自動對其值進行遞增的列。在DataSet 中使用自動增量的列時,如果自動增量的列來自數據源,可避免添加到DataSet 的行和添加到數據源的行之間本地編號沖突。

例如一個表,它的主鍵列CustomerID 是自動增量的。兩個新的客戶信息行添加到表中,并接收到自動增量的CustomerID 值1 和2。然后,只有第二個客戶行被傳遞給DataAdapter 的方法Update,新添加的行在數據源接收到一個自動增量的CustomerID 值1,與DataSet 中的值2 不匹配。當DataAdapter 用返回值填充表中第二行時,就會出現約束沖突,因為第一個客戶行已經使用了CustomerID 值1。

要避免這種情況,建議把DataSet 中的列創(chuàng)建為AutoIncrementStep 值等于-1 并且AutoIncrementSeed 值等于0,另外,還要確保數據源生

成的自動增量標識值從1 開始,并且以正階值遞增。

CommandBuilder 的使用
在設計階段不要使用CommandBuilder,否者產生DataAdapter Command屬性的進程將會受到干擾。? CommandBuilder使用SelectCommand決定其他Command屬性的值。如果DataAdapter的SelectCommand本身發(fā)生變化,應該使用RefreshSchema去刷新Command的屬性。

只要DataAdapter的Command屬性為空,CommandBuilder就僅僅創(chuàng)建一個Command,即使你明確地指定Command的屬性值,CommandBuilder也不會重寫,所以如果你想創(chuàng)建一個Command并保留以前的屬性設置,那么就把Command的屬性設置為null。

QA
Q: 適配器事件的例子,應該是更新前查看是否有其他的用戶已修改了"數據庫",而不是"數據集"吧?

A:對,是數據庫。

 

Q:在智能客戶端中,有多個客戶端對服務器端上的數據進行增、刪、改操作,客戶端可以脫機進行操作,通過計時器與服務器同步數據 在一個客戶端上怎樣把別的客戶端刪除的記錄同步到本地呢?

A:建議把客戶端用戶對服務器數據庫中的刪除不做真正刪除,只是做刪除標記。這樣就可以把它同步到本地了。

 

Q: 在更新表時出錯,是否是因為被更新的表沒有設置主鍵?

A:對。通常情況如果沒有設置主鍵,會更新失敗。

 

Q: DataSet有多行(n行)需要被更新時,調用DataAdapter的Update方法后,RowUpdated事件,是觸發(fā)一次,還是觸發(fā)多次(n次)?

A:觸發(fā)n次,每更新一行都觸發(fā)。

 

Q: DataAdapter中的Command似乎不是很靈活(我是指只能寫死在代碼嗎?),我是想,能不能通過配置文件來?這樣會比較靈活!

A:可以把他寫到XML文件中,讀入XML文件,得到對應的Command,也是可以的。

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多