|
http://www.cnblogs.com/kissknife/archive/2008/11/17/1335271.html
1、ADO.NET相關(guān)對(duì)象一句話介紹 1)DataAdapter: DataAdapter實(shí)際是一個(gè)SQL語(yǔ)句集合,因?yàn)閷?duì)Database的操作最終需要?dú)w結(jié)到SQL語(yǔ)句。 2)Dataset: DataSet可以理解成若干DataTable的集合,DataSet在內(nèi)存里面維護(hù)一個(gè)表集合包括表間關(guān)系。對(duì)于.NET Framework 2.0之前的版本,DataSet在ADO.NET中擁有至關(guān)重要的作用,但在其后的版本中,由于DataTable類(lèi)的完備(例如與XML相關(guān)的幾個(gè)方法以及Merge方法),其作用稍有削弱,甚至于有些情況下你去初始化一個(gè)DataSet對(duì)象本身就是多余的。 3)DataView: 與數(shù)據(jù)庫(kù)中的視圖在概念上是類(lèi)似的。DataView本身并不真正包含數(shù)據(jù)行,而只是包含指向源DataTable中數(shù)據(jù)行的引用,這一點(diǎn)你可以通過(guò)object.ReferenceEquals()方法來(lái)驗(yàn)證。 4)DataTable: ADO.NET的核心對(duì)象。它是位于內(nèi)存中的一張表,是你執(zhí)行SQL查詢(xún)之后的結(jié)果集,可以形象地把它理解為一張包含若干行若干列的表格。 2、如何更新數(shù)據(jù)到Database 從本質(zhì)上來(lái)說(shuō),你對(duì)Database操作總是歸結(jié)到SQL語(yǔ)句,但是從表面上我們可以作一點(diǎn)區(qū)分, 1)直接使用SQL命令 在.NET中,最常見(jiàn)的是拼接SQL字符串,使用Command對(duì)象來(lái)執(zhí)行此命令以達(dá)到操作Database的目的,例如, string sql = "update table1 set fvalue=" + this.textBox1.Text + " where fname='x'"; SqlCommand cmd = new SqlCommand(sql,conn); cmd.ExecuteNonQuery(); 這是一種最直接淺顯的方式,因?yàn)?/span>SQL語(yǔ)句就在你眼前,反過(guò)來(lái)說(shuō),這需要你對(duì)SQL命令有一定的了解。
2)使用DataAdapter.Update() 另外一種方式,是使用DataAdapter.Update()方法,這并不是說(shuō)我們不需要SQL語(yǔ)句了,只是SQL語(yǔ)句拼接的工作已經(jīng)交給了DataAdapter(實(shí)際上是交給了CommandBuilder)來(lái)完成(以參數(shù)的形式),例如, string c = "select fname,fvalue from table1"; SqlCommand cmd = new SqlCommand(c,conn); SqlDataAdapter da = new SqlDataAdapter(cmd); SqlCommandBuilder scb = new SqlCommandBuilder(da); //(1) DataTable dt = new DataTable(); da.Fill(dt); dt.Rows[0].Delete();//(2) da.Update(dt); 在這里,你看不到SQL語(yǔ)句,因?yàn)樵谀愠跏蓟?/span>SqlCommandBuilder的過(guò)程中,將自動(dòng)根據(jù)表結(jié)構(gòu)(基于你的Select語(yǔ)句)構(gòu)造insert,update,delete語(yǔ)句。對(duì)于上面的代碼,你可以獲得SQL語(yǔ)句內(nèi)容,
DELETE FROM [table1] WHERE (([fname] = @p1) AND ((@p2 = 1 AND [fvalue] IS NULL) OR ([fvalue] = @p3))) 而執(zhí)行時(shí)候,會(huì)傳入相應(yīng)的參數(shù)值, exec sp_executesql N'DELETE FROM [table1] WHERE (([fname] = @p1) AND ((@p2 = 1 AND [fvalue] IS NULL) OR ([fvalue] = @p3)))',N'@p1 varchar(1),@p2 int,@p3 int',@p1='a',@p2=0,@p3=100 或 xec sp_executesql N'DELETE FROM [table1] WHERE (([fname] = @p1) AND ((@p2 = 1 AND [fvalue] IS NULL) OR ([fvalue] = @p3)))',N'@p1 varchar(1),@p2 int,@p3 int',@p1='b',@p2=1,@p3=NULL 由于表中只有兩個(gè)列,列fname為主鍵列,fvalue列可空,至于為什么會(huì)出現(xiàn)三個(gè)參數(shù),看看上面的SQL你就會(huì)明白了。 以下則分別是update語(yǔ)句、insert語(yǔ)句, UPDATE [table1] SET [fname] = @p1, [fvalue] = @p2 WHERE (([fname] = @p3) AND ((@p4 = 1 AND [fvalue] IS NULL) OR ([fvalue] = @p5))) INSERT INTO [table1] ([fname], [fvalue]) VALUES (@p1, @p2) 另外,上述C#代碼中的dt.Rows[0].Delete()行寫(xiě)在這里只是示例作用,實(shí)際的系統(tǒng)中,你可能會(huì)有一個(gè)叫“Delete”的按鈕,這樣你可以在按鈕的事件中執(zhí)行Delete()操作,然后叫某個(gè)叫“Save”的按鈕里寫(xiě)上Update(),這很常見(jiàn),不多說(shuō)了。 再另外,由于這些語(yǔ)句的構(gòu)造過(guò)程中依賴(lài)于你的Select語(yǔ)句,所以你的Select語(yǔ)句中必須包含主鍵列,否則無(wú)法正常生成其它SQL命令。 以下我們的討論,將主要針對(duì)第二種方式,即使用Update()進(jìn)行數(shù)據(jù)更新過(guò)程中涉及的各種問(wèn)題。 3、行狀態(tài) 為了后續(xù)的數(shù)據(jù)操作,DataTable中引入了一個(gè)“行狀態(tài)”的概念(事實(shí)上該屬性屬于DataRow類(lèi))。每一個(gè)DataRow都有一個(gè)狀態(tài)標(biāo)志,你可以通過(guò)DataTable.Rows[i].RowState查看,對(duì)DataRow的不同操作將導(dǎo)致該行處于不同的狀態(tài),同時(shí),不同的狀態(tài)又導(dǎo)致保存數(shù)據(jù)時(shí)的不同行為。參見(jiàn)下圖, 1)初始狀態(tài)差異 從數(shù)據(jù)庫(kù)中查詢(xún)并通過(guò)DataAdapter.Fill()方法填充的DataTable,其所有行的狀態(tài)初始都為Unchanged(我們可以認(rèn)為在Fill()方法的內(nèi)部調(diào)用了AcceptChanges()方法),然而對(duì)于在程序中手工構(gòu)造并添加的數(shù)據(jù)行,在未接受AcceptChanges()方法前,都為Added(行狀態(tài)的不同在DataTable中是一個(gè)比較隱蔽的但又需要十分關(guān)注的問(wèn)題,后續(xù)會(huì)有相應(yīng)的說(shuō)明),參見(jiàn)以下代碼。 private void button1_Click(object sender, EventArgs e) { try { dataAdapter1.Fill(dt); DataRowState s = dt.Rows[0].RowState;//unchanged } catch { } } private void button2_Click(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Add("fname"); dt.Columns.Add("fvalue"); dt.Rows.Add("zhang", 100); DataRowState s = dt.Rows[0].RowState;//added } 此方法并未真正移除DataRow(除非此行原狀態(tài)為Added),而只是將RowState狀態(tài)變成了Deleted(當(dāng)然這會(huì)導(dǎo)致你無(wú)法使用正常的索引方式訪問(wèn)此行的數(shù)據(jù))。對(duì)于Added狀態(tài)的行執(zhí)行Delete()操作,將導(dǎo)致DataTable行數(shù)減少,這點(diǎn)需要注意,因?yàn)樗赡軐?dǎo)致你在使用for循環(huán)遍歷時(shí)出現(xiàn)索引越界異常。 private void button7_Click(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Add("fname"); dt.Columns.Add("fvalue"); dt.Rows.Add("zhang", 100); // dt.Rows[0].Delete(); int c = dt.Rows.Count;//0 } private void button8_Click(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Add("fname"); dt.Columns.Add("fvalue"); dt.Rows.Add("zhang", 100); // dt.AcceptChanges(); dt.Rows[0].Delete(); int c = dt.Rows.Count;//1 } 3)Exception:Deleted row information cannot be accessed through the row. private void button8_Click(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Add("fname"); dt.Columns.Add("fvalue"); dt.Rows.Add("zhang", 100); // dt.AcceptChanges(); dt.Rows[0].Delete(); DataRow dr = dt.Rows[0]; //No error object o = dt.Rows[0]["fvalue"];//Exception,row can be accessed,but row data cannot } 4)理解AcceptChanges() 此方法容易給人誤解,以為在調(diào)用它之后對(duì)DataTable所做的所有更改將會(huì)被提交到Database。事實(shí)上,此方法跟Database沒(méi)有直接的關(guān)系(注意),它只直接影響各DataRow的RowState(具體地說(shuō)來(lái)是將所有狀態(tài)為Deleted的行真正移除,所有狀態(tài)為Added或Modified的行都變成Unchanged)。與Database有直接相關(guān)的是DataAdapter.Update()方法,它是真正負(fù)責(zé)執(zhí)行相關(guān)SQL命令的地方。 但是,從另一方面來(lái)說(shuō),沒(méi)有直接的影響,言外之意就是有間接的影響,由于它影響了所有DataRow的RowState,而DataAdapter.Update()方法在執(zhí)行SQL命令時(shí)必須依據(jù)RowState以確定使用insert、update、或delete 命令。舉個(gè)例子,如果你在DataAdapter.Update()調(diào)用之前執(zhí)行AcceptChanges()方法,這將阻止所有對(duì)Database的更改,因此對(duì)這兩個(gè)方法調(diào)用的順序應(yīng)有充分的考慮。 另外,DataSet、DataTable、DataRow都有AcceptChanges()方法,這些方法除了影響的范圍大小不同之外,沒(méi)有本質(zhì)的區(qū)別。 5)DataRowState與Update() 不同的數(shù)據(jù)行狀態(tài),將導(dǎo)致最終DataAdapter.Update()出現(xiàn)不同的行為,例如對(duì)于Added狀態(tài)的行,將導(dǎo)致insert操作、Modified狀態(tài)將導(dǎo)致update操作、Deleted狀態(tài)將導(dǎo)致delete操作。 6)使用DataRowState 除了Update()方法內(nèi)部使用DataRowState外,在我們自己寫(xiě)的代碼中,也可以將它與GetChanges()方法配合使用,以獲取DataTable的當(dāng)前變化,參見(jiàn)以下代碼,在你獲得所有發(fā)生更新的行后,實(shí)際上你可以自己構(gòu)造Update SQL命令,而不使用CommandBuilder,當(dāng)然這需要用到稍后會(huì)提到的DataRowVersion。 private void button4_Click(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Add("fname"); dt.Columns.Add("fvalue"); dt.Rows.Add("zhang", 100); dt.AcceptChanges(); dt.Rows[0]["fvalue"] = 101 //get all Modified rows,then you can use UPDATE SQL to save data. DataTable dt1 = dt.GetChanges(DataRowState.Modified); } 7)狀態(tài)Detached 除了上圖中給出的幾種行狀態(tài)外,還有一種特殊的狀態(tài)Detached,這種狀態(tài)表示已初始化但未添加到DataTable中的數(shù)據(jù)行,此狀態(tài)我們不必太關(guān)心。參見(jiàn), private void button3_Click(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Add("fname"); dt.Columns.Add("fvalue"); DataRow dr = dt.NewRow(); DataRowState s = dr.RowState;//detached } 4、行狀態(tài)、行版本、行數(shù)據(jù)版本 行版本(DataRowVersion)描述數(shù)據(jù)行的版本; 行數(shù)據(jù)版本(DataViewRowState)描述數(shù)據(jù)行中數(shù)據(jù)的版本。 這兩個(gè)概念令人困惑,我認(rèn)為可以?xún)H僅從用法上對(duì)它們進(jìn)行了解,畢竟我們使用它們的機(jī)會(huì)并非很大。 1)使用DataRowVersion 關(guān)于DataRowVersion,以狀態(tài)為Modified的行為例,它包含兩個(gè)DataRowVersion(即存儲(chǔ)了兩行數(shù)據(jù)):Current,Original,分別存儲(chǔ)該行修改后與修改前的數(shù)據(jù),也就是說(shuō),行版本實(shí)際可以幫助RejectChanges()等方法實(shí)現(xiàn)一個(gè)類(lèi)似于“回滾”的功能。 private void button4_Click(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Add("fname"); dt.Columns.Add("fvalue"); dt.Rows.Add("zhang", 100); dt.AcceptChanges(); dt.Rows[0]["fvalue"] = 101; int i = Convert.ToInt32(dt.Rows[0]["fvalue", DataRowVersion.Original]);//100 int i2 = Convert.ToInt32(dt.Rows[0]["fvalue", DataRowVersion.Current]);//101 } 同理你可以借助DataRowVersion來(lái)訪問(wèn)Deleted的數(shù)據(jù),前面我們提到了對(duì)于Deleted的數(shù)據(jù),使用dt.Rows[0]["fvalue"]訪問(wèn)將引發(fā)異常,可以使用
dt.Rows[0]["fvalue", DataRowVersion.Original]。 2) DataRowVersion與Update() 現(xiàn)在我們回想一下,當(dāng)我們使用CommandBuilder構(gòu)造完Update,Insert,Delete命令之后,那些SQL命令中的參數(shù)怎么辦?我們知道在SQL命令執(zhí)行之前,我們必須為所有輸入?yún)?shù)指定參數(shù)值,那么Update()方法內(nèi)部是如何工作的?這就有賴(lài)于DataRowVersion了。 我們可以簡(jiǎn)單看一下Update()方法使用過(guò)程中涉及的相關(guān).NET源碼, System.Data.Common.DbDataAdapter protected virtual int Update(DataRow[] dataRows, DataTableMapping tableMapping); 在Update()方法中,調(diào)用了ParameterInput(),下面是該方法的摘要, System.Data.Common.DbDataAdapter private void ParameterInput(IDataParameterCollection parameters, StatementType typeIndex, DataRow row, DataTableMapping mappings) { foreach (IDataParameter parameter in parameters) { if (column != null) { DataRowVersion parameterSourceVersion = GetParameterSourceVersion(typeIndex, parameter); parameter.Value = row[column, parameterSourceVersion]; } } } 在ParameterInput()方法中,調(diào)用了GetParameterSourceVersion()方法,
System.Data.Common.DbDataAdapter private static DataRowVersion GetParameterSourceVersion(StatementType statementType, IDataParameter parameter) { switch (statementType) { case StatementType.Select: case StatementType.Batch: throw ADP.UnwantedStatementType(statementType); case StatementType.Insert: return DataRowVersion.Current; case StatementType.Update: return parameter.SourceVersion; case StatementType.Delete: return DataRowVersion.Original; } throw ADP.InvalidStatementType(statementType); } 以行被更新的情況為例,在為參數(shù)的賦值的過(guò)程中,系統(tǒng)會(huì)將相應(yīng)要更新的DataRow一并傳入,同時(shí)對(duì)于Update語(yǔ)句,
UPDATE [table1] SET [fname] = @p1, [fvalue] = @p2 WHERE (([fname] = @p3) AND ((@p4 = 1 AND [fvalue] IS NULL) OR ([fvalue] = @p5))) 我們要了解的一點(diǎn)是,5個(gè)參數(shù)中@p1,@p2是一類(lèi),@p3, @p5是一類(lèi),它們的區(qū)別在于,前一類(lèi)的SourceVersion是Current,而后一類(lèi)的SourceVersion是Original,這在上述的GetParameterSourceVersion()方法中被用到,所以!!,針對(duì)傳入的需要更新的DataRow,Update()方法內(nèi)部將使用當(dāng)前值(即修改后的值)填充@p1,@p2,而使用原始值(即修改前的值)填充@p3, @p5。Insert,delete同理。 3)理解DataRowVersion.Default 對(duì)于Added、Modified、Deleted狀態(tài)的行,其Default版本實(shí)際是Current版本,對(duì)于Unchanged則無(wú)甚區(qū)別。 4)使用DataViewRowState (1)配合DataTable.Select() private void button9_Click(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Add("fname"); dt.Columns.Add("fvalue"); dt.Rows.Add("zhao", 100); dt.Rows.Add("qian", 100); dt.Rows.Add("sun", 100); dt.AcceptChanges(); // dt.Rows[1]["fvalue"] = 101; dt.Rows[2].Delete(); dt.Rows.Add("li", 100); //object o = dt.Rows[2]["fvalue", DataRowVersion.Original]; // StringBuilder sb = new StringBuilder(); DataRow[] drs = dt.Select(null, null, DataViewRowState.Added); sb.AppendLine("-----------------------------------------------"); sb.AppendLine("Added:"); for (int i = 0; i < drs.Length; i++) { sb.AppendLine(drs[i]["fname"].ToString() +": "+ drs[i]["fvalue"].ToString()); } drs = dt.Select(null, null, DataViewRowState.CurrentRows); sb.AppendLine("-----------------------------------------------"); sb.AppendLine("CurrentRows:"); for (int i = 0; i < drs.Length; i++) { sb.AppendLine(drs[i]["fname"].ToString() + ": " + drs[i]["fvalue"].ToString()); } drs = dt.Select(null, null, DataViewRowState.Deleted); sb.AppendLine("-----------------------------------------------"); sb.AppendLine("Deleted:"); for (int i = 0; i < drs.Length; i++) { sb.AppendLine(drs[i]["fname", DataRowVersion.Original].ToString() + ": " + drs[i]["fvalue", DataRowVersion.Original].ToString()); } drs = dt.Select(null, null, DataViewRowState.ModifiedCurrent); sb.AppendLine("-----------------------------------------------"); sb.AppendLine("ModifiedCurrent:"); for (int i = 0; i < drs.Length; i++) { sb.AppendLine(drs[i]["fname"].ToString() + ": " + drs[i]["fvalue"].ToString()); } drs = dt.Select(null, null, DataViewRowState.ModifiedOriginal); sb.AppendLine("-----------------------------------------------"); sb.AppendLine("ModifiedOriginal:"); for (int i = 0; i < drs.Length; i++) { sb.AppendLine(drs[i]["fname"].ToString() + ": " + drs[i]["fvalue"].ToString()); } drs = dt.Select(null, null, DataViewRowState.OriginalRows); sb.AppendLine("-----------------------------------------------"); sb.AppendLine("OriginalRows:"); for (int i = 0; i < drs.Length; i++) { if (drs[i].RowState == DataRowState.Deleted) { sb.AppendLine(drs[i]["fname", DataRowVersion.Original].ToString() + ": " + drs[i]["fvalue", DataRowVersion.Original].ToString()); } else { sb.AppendLine(drs[i]["fname"].ToString() + ": " + drs[i]["fvalue"].ToString()); } } drs = dt.Select(null, null, DataViewRowState.Unchanged); sb.AppendLine("-----------------------------------------------"); sb.AppendLine("Unchanged:"); for (int i = 0; i < drs.Length; i++) { sb.AppendLine(drs[i]["fname"].ToString() + ": " + drs[i]["fvalue"].ToString()); } MessageBox.Show(sb.ToString()); } 結(jié)果輸出: ----------------------------------------------- Added: li: 100 ----------------------------------------------- CurrentRows: zhao: 100 qian: 101 li: 100 ----------------------------------------------- Deleted: sun: 100 ----------------------------------------------- ModifiedCurrent: qian: 101 ----------------------------------------------- ModifiedOriginal: qian: 101 ----------------------------------------------- OriginalRows: zhao: 100 qian: 101 sun: 100 ----------------------------------------------- Unchanged: zhao: 100 (2)配合DataView.RowFilter private void button10_Click(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Add("fname"); dt.Columns.Add("fvalue"); dt.Rows.Add("zhao", 100); dt.Rows.Add("qian", 100); dt.Rows.Add("sun", 100); dt.AcceptChanges(); // dt.Rows[1]["fvalue"] = 101; dt.Rows[2].Delete(); dt.Rows.Add("li", 100); // DataView dv = new DataView(dt); dv.RowStateFilter = DataViewRowState.Added | DataViewRowState.ModifiedCurrent; StringBuilder sb = new StringBuilder(); sb.AppendLine("-----------------------------------------------"); sb.AppendLine("Added & ModifiedCurrent:"); for (int i = 0; i < dv.Count; i++) { sb.AppendLine(dv[i]["fname"].ToString() + ": " + dv[i]["fvalue"].ToString()); } sb.AppendLine("-----------------------------------------------"); MessageBox.Show(sb.ToString()); } //-----------------------------------------------
Added & ModifiedCurrent: qian: 101 li: 100 ----------------------------------------------- 5)DataViewRowState中的“復(fù)合版本” DataViewRowState包含多個(gè)枚舉成員,我可以給出每個(gè)枚舉成員對(duì)應(yīng)的int值, Added 4 CurrentRow 22 Deleted 8 ModifiedCurrent 16 ModifiedOriginal 32 None 0 OriginalRow 42 Unchanged 2 你可以發(fā)現(xiàn),其中的兩個(gè)狀態(tài)CurrentRow、OriginalRow實(shí)際是經(jīng)由其它幾種狀態(tài)二進(jìn)制或運(yùn)算的結(jié)果, CurrentRow=Added|ModifiedCurrent|Unchanged, OriginalRow=Deleted|ModifiedOriginal|Unchanged。 5、了解其它幾個(gè)方法 1)Delete()、Remove()、Clear() DataRow.Delete(); DataRowCollection.Remove(); DataTable.Clear()、DataSet.Clear() 正如前面所述,對(duì)于DataRow的Delete()方法,其內(nèi)部的處理并未真正刪除此行,而只是將行標(biāo)識(shí)為Deleted,并“移除”了它的Current版本。這樣,當(dāng)使用DataAdapter的Update()進(jìn)行更新時(shí),其內(nèi)部機(jī)制可以根據(jù)仍然存在的Original版本數(shù)據(jù),為DeleteCommand填充參數(shù),完成更新數(shù)據(jù)庫(kù)的操作。 而Clear()方法則完全刪除了堆上的數(shù)據(jù)行對(duì)象,并且將對(duì)數(shù)據(jù)引用置空(這點(diǎn)可以參見(jiàn)Clear()方法的反編譯代碼),這種情況下無(wú)法生成可執(zhí)行的DeleteCommand,這就是說(shuō),當(dāng)你用Clear()方法“清空”DataTable后,使用Update()方法并不能像你預(yù)想的一樣將對(duì)應(yīng)的數(shù)據(jù)庫(kù)表數(shù)據(jù)刪除。 另外,需要注意一點(diǎn)是Delete()并不導(dǎo)致數(shù)據(jù)行減少(除非原行是Added狀態(tài)),當(dāng)然,如果是對(duì)Added狀態(tài)的行執(zhí)行Delete(),則導(dǎo)致行數(shù)減少。當(dāng)你使用for循環(huán)時(shí),這可能會(huì)造成問(wèn)題。 另外,我們還有一個(gè)方法:DataRowCollection.Remove(),其作用類(lèi)似于Clear(),是徹底地移除行,假設(shè)你是使用DataAdapter.Update()方法更新Database,那么你將沒(méi)有機(jī)會(huì)將你的刪除操作同步到Database中。 2)Copy()、Clone() .NET中有兩類(lèi)拷貝,淺拷貝(Shadow copy)、深拷貝(Deep copy),對(duì)于大多數(shù)我們所見(jiàn)的類(lèi)(比如常見(jiàn)的集合類(lèi)等等),沒(méi)有深拷貝方法,大多數(shù)會(huì)有一個(gè)淺拷貝方法Clone()。我唯一所見(jiàn)的一個(gè)深拷貝方法是DataTable.Copy(),同時(shí),DataTable.Clone()方法也比較特殊,因?yàn)樗⒎鞘菧\拷貝方法,而是拷貝DataTable的結(jié)構(gòu)(不包含數(shù)據(jù))。 順便提一下深、淺拷貝的區(qū)別,淺拷貝創(chuàng)建原對(duì)象類(lèi)型的一個(gè)新實(shí)例,復(fù)制原對(duì)象的所有值類(lèi)型成員,對(duì)于引用類(lèi)型成員,則只復(fù)制該值的指針。深拷貝則復(fù)制原對(duì)象的所有成員,對(duì)于引用類(lèi)型成員,亦復(fù)制其所指的堆上的對(duì)象。 static void Main(string[] args) { DataTable dt = new DataTable(); dt.Columns.Add("fname", typeof(System.String)); dt.Columns.Add("fvalue", typeof(System.Int32)); for (int i = 1; i <= 10; i++) { dt.Rows.Add("p" + i, i); } dt.AcceptChanges(); // DataTable dtc = dt.Copy(); // bool b = object.ReferenceEquals(dt.Rows[0], dtc.Rows[0]);//false DataRowState s = dtc.Rows[0].RowState;//Unchanged //Clone() and ImportRow() DataTable dtc2 = dt.Clone(); for (int i = 0; i < 5; i++) { dtc2.ImportRow(dt.Rows[i]); } bool b2 = object.ReferenceEquals(dt.Rows[0], dtc2.Rows[0]);//false DataRowState s2 = dtc2.Rows[0].RowState;//Unchanged //ItemArray DataTable dtc3 = dt.Clone(); for (int i = 0; i < 5; i++) { dtc3.Rows.Add(dt.Rows[i].ItemArray); //dtc3.Rows.Add(dt.Rows[i]);//run time exception } bool b5 = object.ReferenceEquals(dt.Rows[0], dtc3.Rows[0]);//false DataRowState s5 = dtc3.Rows[0].RowState;//Added // ArrayList al = new ArrayList(); al.Add("xy"); ArrayList alc = al.Clone() as ArrayList; if (alc != null) { bool b3 = object.ReferenceEquals(al, alc);//false bool b4 = object.ReferenceEquals(al[0], alc[0]);//true } } 3)Select()、Compute() 這兩個(gè)方法在很多情況下都有助于你簡(jiǎn)化代碼,避免每一次使用循環(huán)遍歷DataTable,參見(jiàn)以下, 對(duì)于這兩個(gè)方法中可用的表達(dá)式,參見(jiàn), http://msdn.microsoft.com/en-us/library/system.data.datacolumn.expression.aspx class Program { static void Main(string[] args) { DataTable dt = new DataTable(); dt.Columns.Add("fname",typeof(System.String)); dt.Columns.Add("fvalue",typeof(System.Int32)); for (int i = 1; i <= 10; i++) { dt.Rows.Add("p" + i, i); } dt.AcceptChanges(); // DataRow[] drs = dt.Select("fvalue>6"); PrindRows(drs); // drs = dt.Select("fvalue>6 and fvalue<9");//AND OR NOT PrindRows(drs); // drs = dt.Select("fname like 'p1%'"); PrindRows(drs); // drs = dt.Select("fname in ('p1','p3')");//< > <= >= <> = IN LIKE PrindRows(drs); // drs = dt.Select("fvalue=max(fvalue)");//SUM AVG MIN MAX COUNT STDEV VAR PrindRows(drs); // drs = dt.Select("fvalue%2=0");//+ - * / % PrindRows(drs); // drs = dt.Select("len(fname)=3");//LEN(expression) ISNULL(expression, replacementvalue) IIF(expr, truepart, falsepart) TRIM(expression) SUBSTRING(expression, start, length) PrindRows(drs); object o = dt.Compute("count(fname)", "fvalue>6");//4 Console.WriteLine(o.ToString()); Console.Read(); } static void PrindRows(DataRow[] pDrs) { Console.WriteLine("----------------------------------"); foreach (DataRow dr in pDrs) { Console.WriteLine(dr["fname"].ToString().PadRight(8, ' ') + dr["fvalue"].ToString()); } Console.WriteLine("----------------------------------"); } } ---------------------------------- p7 7 p8 8 p9 9 p10 10 ---------------------------------- ---------------------------------- p7 7 p8 8 ---------------------------------- ---------------------------------- p1 1 p10 10 ---------------------------------- ---------------------------------- p1 1 p3 3 ---------------------------------- ---------------------------------- p10 10 ---------------------------------- ---------------------------------- p2 2 p4 4 p6 6 p8 8 p10 10 ---------------------------------- ---------------------------------- p10 10 ----------------------------------
|
|
|
來(lái)自: 隱形的翅膀 > 《我的圖書(shū)館》