处理数据集

it2024-11-12  15

数据集(Dataset)对象包括DataTableCollection、DataRelationCollection对象。

DataTableCollection对象包含一或多个DataTable对象。DataTable对象又是由DataRowCollection、DataColumnCollection、ConstraintCollection对象组成。

现在,我们来看DataTable对象。

DataTable对象

DataTable对象将表格化数据表示为内存中的一个包含行、列、约束的表。通过创建DataTable类的一个实例,可以向其中添加、删除、修改数据.

现在,我们首先创建一个Employee的表对象,然后向该表中添加列,并设置主键,随后,向其中添加数据.

创建Employee表对象

//创建DataTable对象 DataTable Employee = new DataTable("Employee");

为Employee表添加EmployeeNo、EmployeeName、EmployeeAge、EmployeeDepartmentNo、EmployeeScore列:

DataColumn EmployeeNo = new DataColumn("EmployeeNo", typeof(string)); EmployeeNo.Unique = true; EmployeeNo.AllowDBNull = false; Employee.Columns.Add(EmployeeNo); DataColumn EmployeeName = new DataColumn("EmployeeName", typeof(string)); EmployeeName.AllowDBNull = false; Employee.Columns.Add(EmployeeName); DataColumn EmployeeAge = new DataColumn("EmployeeAge", typeof(Int32)); Employee.Columns.Add(EmployeeAge); DataColumn EmployeeDepartmentNo = new DataColumn("EmployeeDepartmentNo", typeof(string)); Employee.Columns.Add(EmployeeDepartmentNo); DataColumn EmployeeScore = new DataColumn("EmployeeScore", typeof(decimal)); Employee.Columns.Add(EmployeeScore);

为Employee表设置主键

一个DataTable对象的主键是由一个或多个列组成的,用于唯一标识每个数据行.

在上面的代码中,我们可以将EmployeeNo设置为该表的主键.

//注意: // 因为表的主键可能是由一个或多个列组成的,所以该属性实际上是一个列的数组 Employee.PrimaryKey = new DataColumn[] { EmployeeNo };

向Employee表中添加数据

//向Employee表中添加第一条数据 DataRow rowZhangSan = Employee.NewRow(); rowZhangSan["EmployeeNo"] = "1"; rowZhangSan["EmployeeName"] = "张三"; rowZhangSan["EmployeeAge"] = 30; rowZhangSan["EmployeeDepartmentNo"] = "1"; rowZhangSan["EmployeeScore"] = 100; Employee.Rows.Add(rowZhangSan); //向Employee表中添加第二条数据 Employee.Rows.Add("2", "李四", 25, "2", 90); //向Employee表中添加第三条数据 Employee.LoadDataRow(new object[] { "1", "王五", 28, "3", 95 }, LoadOption.OverwriteChanges);

使用DataRowState查看DataRow对象的状态

//输出结果: //张三   Unchanged //李四   Unchanged //王五   Unchanged foreach (DataRow row in Employee.Rows) { Response.Write(row["EmployeeName"].ToString().PadRight(5,' ') + row.RowState.ToString() + "<br/>"); }

此处介绍一下DataRowState.DataRow对象包含一系列状态,可以在任何时候查看并筛选这些状态.

通过DataRow.RowState属性可以获取DataRow对象的当前状态,该属性包含一个DataRowState枚举.该枚举取值如下:

RowState的值描述Detached已经创建了DataRow对象,但是还没有将其添加到DataTable中的DataRow对象的状态Added已经创建了DataRow对象,并已经将其加入到DataTable中的DataRow对象的状态Unchanged自上一次调用AccepChanges方法后,还没有修改的DataRow对象的状态.调用AccepChanges方法,该DataTable中的所有Row都变为Unchanged状态.Modified自上一次调用AcceptChanges方法后,已经修改的DataRow对象的状态Deleted使用DataRow类的Delete方法删除的DataRow对象的状态.

我们接着"为Employee表设置主键"代码段后,重新添加数据.添加代码如下:

//创建DataRow对象 DataRow rowZhangSan = Employee.NewRow(); rowZhangSan["EmployeeNo"] = "1"; rowZhangSan["EmployeeName"] = "张三"; rowZhangSan["EmployeeAge"] = 30; rowZhangSan["EmployeeDepartmentNo"] = "1"; rowZhangSan["EmployeeScore"] = 100; //结果如下: // Detached DisplayRowState(rowZhangSan); //向Employee表中添加数据rowZhangSan //结果如下: // Added DisplayRowState(Employee.Rows.Add, rowZhangSan); //调用AcceptChanges方法 //结果如下: // Unchanged DisplayRowState(Employee.AcceptChanges, rowZhangSan); rowZhangSan["EmployeeScore"] = 90; //结果如下: // Modified DisplayRowState(rowZhangSan); //回滚至上一次加载后的结果 //结果如下: // Unchanged DisplayRowState(Employee.RejectChanges, rowZhangSan); //删除该行 //结果如下: // Deleted DisplayRowState(rowZhangSan.Delete, rowZhangSan);

其中使用了方法DisplayRowState,其代码如下:

void DisplayRowState(DataRow row) { Response.Write(row.RowState.ToString() + "<br/>"); } void DisplayRowState(Action action,DataRow row) { action(); this.DisplayRowState(row); } void DisplayRowState(Action<DataRow> action, DataRow row) { action(row); this.DisplayRowState(row); }

我们看到,上面的例子中有一个RejectChanges方法,该方法可以将数据回滚至上次AcceptChanges之后的数据状态.

那么,我们能否这样调用Employee.RejectChanges().RejectChanges()来回滚至上上次的AcceptChanges之后的数据状态呢.

答案是不行的,这就关系到了DataRow对象的三个版本的数据.请看下面的"使用DataRowVersion管理数据的多个版本".

使用DataRowVersion管理数据的多个版本

DataRow对象包含以下三种版本的数据:Original,Current和Proposed.

在加载DataRow对象时,它仅包含Current版本的数据. 调用BeginEdit方法时,使DataRow对象进入编辑模式,此时,数据保存在Current和Proposed两个版本中. 执行EndEdit方法时,Current版本数据变为Original版本的数据,Proposed版本数据变为Current版本数据,而Proposed版本数据不存在. 执行EndEdit方法后,DataRow对象将包含Original和Current两种版本的数据. 如果再次调用BeginEdit方法,则Current版本的数据将复制为Proposed版本的数据. 如果此时再次调用EndEdit方法,则将使Proposed版本数据变为Current版本的数据.

从DataRow对象获取数据时,可以指定DataRowVersion的值,来获取相应的值.

取值描述Original为原先加载到DataRow对象中的值,或上一次执行了AcceptChanges方法时的值.Current在数据已经发生变化后DataRow对象的当前值.除非DataRow对象的RowState=Deleted,否则该版本的数据在任何时候都存在Proposed在编辑DataRow对象时的值.Default表示默认版本.处于Added,Modified,UnChanged状态行的默认版本是Current处于Deleted状态行的默认版本是Original处于Detached状态行的默认版本是Proposed

我们继续"为Employee表设置主键"段向后,继续添加代码如下:

Employee.LoadDataRow(new object[] { "1", "张三", 30, "1", 100 }, LoadOption.PreserveChanges); DataRow rowZhangSan = Employee.Rows[0]; //LoadDataRow方法后 // EmployeeName:张三  RowState:Unchanged  Version:Original // EmployeeName:张三  RowState:Unchanged  Version:Current // Proposed不存在! // EmployeeName:张三  RowState:Unchanged  Version:Default DisplayRowVersion("LoadDataRow方法后", rowZhangSan); rowZhangSan.BeginEdit(); //调用BeginEdit方法,但未修改数据 // EmployeeName:张三  RowState:Unchanged  Version:Original // EmployeeName:张三  RowState:Unchanged  Version:Current // EmployeeName:张三  RowState:Unchanged  Version:Proposed // EmployeeName:张三  RowState:Unchanged  Version:Default DisplayRowVersion("调用BeginEdit方法,但未修改数据", rowZhangSan); rowZhangSan["EmployeeName"] = "李四"; //调用BeginEdit方法后 // EmployeeName:张三  RowState:Unchanged  Version:Original // EmployeeName:张三  RowState:Unchanged  Version:Current // EmployeeName:李四  RowState:Unchanged  Version:Proposed // EmployeeName:李四  RowState:Unchanged  Version:Default DisplayRowVersion("调用BeginEdit方法后", rowZhangSan); rowZhangSan.EndEdit(); //调用EndEdit方法后 // EmployeeName:张三  RowState:Modified  Version:Original // EmployeeName:李四  RowState:Modified  Version:Current // Proposed不存在! // EmployeeName:李四  RowState:Modified  Version:Default DisplayRowVersion("调用EndEdit方法后", rowZhangSan); Employee.AcceptChanges(); //调用AcceptChanges方法后 // EmployeeName:李四  RowState:Unchanged  Version:Original // EmployeeName:李四  RowState:Unchanged  Version:Current // Proposed不存在! // EmployeeName:李四  RowState:Unchanged  Version:Default DisplayRowVersion("调用AcceptChanges方法后", rowZhangSan); rowZhangSan["EmployeeName"] = "王五"; //修改EmployeeName=王五之后 // EmployeeName:李四  RowState:Modified  Version:Original // EmployeeName:王五  RowState:Modified  Version:Current // Proposed不存在! // EmployeeName:王五  RowState:Modified  Version:Default DisplayRowVersion("修改EmployeeName=王五之后", rowZhangSan); Employee.RejectChanges(); //调用RejectChanges后 // EmployeeName:李四  RowState:Unchanged  Version:Original // EmployeeName:李四  RowState:Unchanged  Version:Current // Proposed不存在! // EmployeeName:李四  DisplayRowVersion("调用RejectChanges后", rowZhangSan); rowZhangSan.Delete(); //删除该行后 // EmployeeName:李四  RowState:Deleted  Version:Original // Current不存在! // Proposed不存在! // Default不存在! DisplayRowVersion("删除该行后", rowZhangSan);

使用DisplayRowVersion代码如下:

void DisplayRowVersion(string state, DataRow row) { Response.Write("<hr/>" + state + "<br/>"); foreach (string version in Enum.GetNames(typeof(DataRowVersion))) { DataRowVersion rowVersion = (DataRowVersion)Enum.Parse(typeof(DataRowVersion), version); try { if (row.HasVersion(rowVersion)) { Response.Write(String.Format("  EmployeeName:{0}  RowState:{1}  Version:{2}<br/>", row["EmployeeName", rowVersion], row.RowState, version)); } else { Response.Write(string.Format("  {0}不存在!<br/>", version)); } } catch (DeletedRowInaccessibleException e) { Response.Write(string.Format("  RowState:{0}  Version{1}  {2}<br/>", row.RowState, version, e.Message)); } } }

现在,我们来看RejectChanges方法调用之后的状态:

Employee.RejectChanges(); //调用RejectChanges后 // EmployeeName:李四  RowState:Unchanged  Version:Original // EmployeeName:李四  RowState:Unchanged  Version:Current // Proposed不存在! // EmployeeName:李四  DisplayRowVersion("调用RejectChanges后", rowZhangSan);

RejectChanges方法可以将Original版本的数据变为Current版本的数据.

上例中调用了RejectChanges方法后,Original版本的数据和Current版本的数据一致.

此时,如果再次调用RejectChanges方法只是将Original版本数据复制到Current版本中,数据无法至再前一个状态的数据.

这也就解答了上面的问题:无法通过调用Employee.RejectChanges().RejectChanges()来回滚至上上次的AcceptChanges之后的数据状态. 

DataView对象

DataView对象是DataTable对象提供的另一个窗口,可以存储和过滤DataTable中的数据,也可以为一个DataTable对象提供多个DataView对象.

DataView对象有以下常用属性:

属性描述RowFilter获取或设置用于筛选DataView对象中数据的表达式Sort获取或设置用于对DataView对象中数据进行排序的表达式

例:

向Employee对象中添加以下数据,然后分别进行筛选和排序

EmployeeNoEmployeeNameEmployeeAgeEmployeeDeparmentEmployeeScore1张三3031002李四201953王五312804赵六343925刘七30191

添加数据及筛选、排序代码如下:

//为Employee表添加数据 Employee.Rows.Add("1", "张三", 30, "3", 100); Employee.Rows.Add("2", "李四", 20, "1", 95); Employee.Rows.Add("3", "王五", 31, "2", 80); Employee.Rows.Add("4", "赵六", 34, "3", 92); Employee.Rows.Add("5", "刘七", 30, "1", 91); DataView dv = Employee.DefaultView; //对DataView对象进行排序 dv.Sort = "EmployeeAge desc,EmployeeScore desc"; //对DataView对象进行筛选 dv.RowFilter = "EmployeeAge>20 and EmployeeScore>80"; //输出结果如下: // 赵六 34 92 // 张三 30 100 // 刘七 30 91 foreach (DataRowView rowView in dv) { Response.Write(rowView["EmployeeName"] + " " + rowView["EmployeeAge"] + " " + rowView["EmployeeScore"] + "<br/>"); }

DataRelation对象

DataRelation对象用于关联同一个DataSet对象中的多个DataTable对象.

在关联DataTable对象时,将创建一条从一个DataTable对象到另一个DataTable对象的路径.

通过编程的方法,可以从父DataTable对象遍历至子DataTable对象,或者从子Datatable对象遍历到父DataTable对象,这样就实现了DataTable对象间的导航.

下面,以例子的形式来理解DataRelation.

我们已经有了一个雇员表,下面,我们再建立一个部门(Deparment)表.表中有DepartmentNo和DepartmentName列,其中DepartmentNo列是主键,并与Employee表中的DepartmentNo关联.本例完整代码如下:

//创建Employee表对象 DataTable Employee = new DataTable("Employee"); //为Employee表添加EmployeeNo、EmployeeName、EmployeeAge、EmployeeDepartmentNo、EmployeeScore列 DataColumn EmployeeNo = new DataColumn("EmployeeNo", typeof(string)); EmployeeNo.Unique = true; EmployeeNo.AllowDBNull = false; Employee.Columns.Add(EmployeeNo); DataColumn EmployeeName = new DataColumn("EmployeeName", typeof(string)); EmployeeName.AllowDBNull = false; Employee.Columns.Add(EmployeeName); DataColumn EmployeeAge = new DataColumn("EmployeeAge", typeof(Int32)); Employee.Columns.Add(EmployeeAge); DataColumn EmployeeDeparmentNo = new DataColumn("EmployeeDeparmentNo", typeof(string)); Employee.Columns.Add(EmployeeDeparmentNo); DataColumn EmployeeScore = new DataColumn("EmployeeScore", typeof(decimal)); Employee.Columns.Add(EmployeeScore); Employee.PrimaryKey = new DataColumn[] { EmployeeNo }; //为Employee表添加数据 Employee.Rows.Add("1", "张三", 30, "3", 100); Employee.Rows.Add("2", "李四", 20, "1", 95); Employee.Rows.Add("3", "王五", 31, "2", 80); Employee.Rows.Add("4", "赵六", 34, "3", 92); Employee.Rows.Add("5", "刘七", 30, "1", 91); //创建Department表 DataTable Department = new DataTable("Department"); //添加DepartmentNo列 DataColumn DepartmentNo = new DataColumn("DepartmentNo", typeof(string)); DepartmentNo.AllowDBNull = false; DepartmentNo.Unique = true; Department.Columns.Add(DepartmentNo); //添加DepartmentName列 DataColumn DepartmentName = new DataColumn("DepartmentName", typeof(string)); Department.Columns.Add(DepartmentName); //为Department表设置主键 Department.PrimaryKey = new DataColumn[] { DepartmentNo }; //为Department表添加数据 Department.Rows.Add("1", "生产部"); Department.Rows.Add("2", "科技部"); Department.Rows.Add("3", "销售部"); //因为DataRelation是同一个DataSet对象中的两个表之间的关联情况 //所以需创建一个DataSet对象 System.Data.DataSet ds = new System.Data.DataSet("ds"); //将Employee表添加入DataSet对象 ds.Tables.Add(Employee); //将Department表添加入DataSet对象 ds.Tables.Add(Department); //添加主外键关系 ds.Relations.Add("Department_Employee", Department.Columns["DepartmentNo"], Employee.Columns["EmployeeDeparmentNo"]); //根据Department遍历到Employee //输出结果如下: // 生产部    // 李四    // 刘七 // 科技部    // 王五 // 销售部    // 张三 // 赵六 foreach (DataRow row in Department.Rows) { Response.Write(row["DepartmentName"].ToString() + "<br/>"); foreach (DataRow r in row.GetChildRows("Department_Employee")) { Response.Write("  " + r["EmployeeName"] + "<br/>"); } } //根据Employee遍历到Department //输出结果: // 张三  销售部 // 李四  生产部 // 王五  科技部 // 赵六  销售部 // 刘七  生产部 foreach (DataRow row in Employee.Rows) { DataRow r = row.GetParentRow("Department_Employee"); Response.Write(row["EmployeeName"] + "  " + r["DepartmentName"] + "<br/>"); }

小结

创建DataTable对象

查看DataRow.RowState

使用DataRowVersion管理数据的多个版本

通过DataView对象对数据进行筛选和排序

使用DataRelation对象加强表之间的关系

转载于:https://www.cnblogs.com/oneword/archive/2010/09/13/1824682.html

最新回复(0)