• 处理数据集


    数据集(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对象加强表之间的关系

  • 相关阅读:
    8.6 First_value和Last_value
    iOS_第3方类库_側滑选项卡SlideSwitchView
    公开的函数把函数作为參数
    .NET 框架简单介绍
    HDU-3577-Fast Arrangement-区间更新
    拥抱PBO(基于项目的组织)聚焦核心价值创造
    一个使用sbt编译的JNI C++ 的模板
    BestCoder Round #1
    饭统网倒闭:不创新、不放权就是作死 .
    【SSH 基础】浅谈Hibernate关系映射(3)
  • 原文地址:https://www.cnblogs.com/oneword/p/1824682.html
Copyright © 2020-2023  润新知