处理数据集

数据集(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.

  1. 在加载DataRow对象时,它仅包含Current版本的数据.
  2. 调用BeginEdit方法时,使DataRow对象进入编辑模式,此时,数据保存在Current和Proposed两个版本中.
  3. 执行EndEdit方法时,Current版本数据变为Original版本的数据,Proposed版本数据变为Current版本数据,而Proposed版本数据不存在.
  4. 执行EndEdit方法后,DataRow对象将包含Original和Current两种版本的数据.
  5. 如果再次调用BeginEdit方法,则Current版本的数据将复制为Proposed版本的数据.
  6. 如果此时再次调用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对象中添加以下数据,然后分别进行筛选和排序

EmployeeNo EmployeeName EmployeeAge EmployeeDeparment EmployeeScore
1 张三 30 3 100
2 李四 20 1 95
3 王五 31 2 80
4 赵六 34 3 92
5 刘七 30 1 91

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

//为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对象加强表之间的关系

你可能感兴趣的:(数据)