# 内存对象 ## 一、DataSet对象 `DataSet` 对象就像存放于内存中的一个小型数据库。它可以包含数据表、数据列、数据行、视图、约束以及关系。 `DataSet` 数据通常来源于数据库或XML,为了从数据库中获取数据,需要使用数据适配器 `DataAdapter` 从数据库中查询数据。 ```csharp //创建DataSet DataSet ds = new DataSet("DataSetDemo"); //创建表1:Student DataTable dt1 = new DataTable("Student"); //表Student中创建列 dt1.Columns.Add("学号", typeof(string)); dt1.Columns.Add("姓名", typeof(string)); dt1.Columns.Add("性别", typeof(string)); dt1.Columns.Add("年龄", typeof(Int16)); dt1.Columns.Add("爱好", typeof(string)); //表Student中添加一行 DataRow dr1 = dt1.NewRow(); dr1["学号"] = "1001"; dr1["姓名"] = "小羽"; dr1["性别"] = "男"; dr1["年龄"] = 9; dr1["爱好"] = "跑步"; dt1.Rows.Add(dr1); //创建表2:Score DataTable dt2 = new DataTable("Score"); //表Score中创建列 dt2.Columns.Add("学号", typeof(string)); dt2.Columns.Add("科目", typeof(string)); dt2.Columns.Add("成绩", typeof(Decimal)); //表Score中添加一行 DataRow dr2 = dt2.NewRow(); dr2["学号"] = "1001"; dr2["科目"] = "语文"; dr2["成绩"] = "95"; dt2.Rows.Add(dr2); //将Student表和Score表添加到DataSet中 ds.Tables.Add(dt1); ds.Tables.Add(dt2); ``` ### 属性 - `Relations`:获取用于将表链接起来并允许从父表浏览到子表的关系的集合。 ```csharp //最后一个参数表示是否创建约束。当参数为true且清空建立关系的DataTable数据时,需要先将DataSet的EnforceConstraints设置为false ds.Relations.Add("成绩", dt1.Columns["学号"], dt2.Columns["学号"], false); ``` - `Tables`:获取包含在 `DataSet` 中的表的集合。 ```csharp string strTableNames = ""; foreach (DataTable dt in ds.Tables) { strTableNames += dt.TableName + " "; } ``` - `ExtendedProperties`:获取或设置用户自定义信息的集合。 ```csharp ds.ExtendedProperties["AvgAge"] = ds.Tables[0].Compute("avg(年龄)", "True"); ``` ### 方法 - `AcceptChanges`:提交自加载此 `DataSet` 或上次调用 `AcceptChanges` 以来对其进行的所有修改。 ```csharp ds.AcceptChanges(); ``` - `Clear`:清除所有表的行数据。 ```csharp ds.Clear(); ``` - `Clone`:复制该 `DataSet` 的结构。 ```csharp DataSet ds1 = ds.Clone(); ``` - `Copy`:复制该 `DataSet` 的结构和数据。 ```csharp DataSet ds1 = ds.Copy(); ``` - `HasChanges`:获取一个值,该值指示 `DataSet` 是否有更改,包括新增行、已删除的行或已修改的行。 ```csharp bool isChange = ds.HasChanges() ``` - `GetChanges`:获取 `DataSet` 的副本,该副本包含自加载以来或自上次调用 `AcceptChanges` 以来对该数据集进行的所有更改。 ```csharp DataSet ds1 = ds.GetChanges(); ds1 = ds.GetChanges(DataRowState.Modified); //带筛选条件 ``` - `Merge`:将指定对象合并到 `DataSet` 中。 ```csharp //合并DataRow DataSet ds1 = ds.Clone(); DataRow[] drs = ds.Tables[0].Select("性别='男'"); ds1.Merge(drs); //合并DataTable DataTable dt1 = ds.Tables[0].Clone(); dt1.Columns.Add("班级", typeof(string)); DataRow dr = dt1.NewRow(); dr["学号"] = "5005"; dr["姓名"] = "小飞"; dr["性别"] = "男"; dr["年龄"] = 9; dr["爱好"] = "跑步"; dr["班级"] = "一班"; dt1.Rows.Add(dr); ds.Merge(dt1, true, MissingSchemaAction.Add); //合并DataSet DataSet ds1 = ds.Copy(); ds.Merge(ds1); ``` ## 二、DataTable对象 `DataTable` 类型定义了许多成员,许多在名称和功能上和 `DataSet` 差不多。一个 `DataSet` 可能包含多个 `DataTable`。 ```csharp //要实例化一个DataRow对象不能使用new DataRow(),应该使用DataTable.NewRow() DataSet ds = new DataSet("DataSetDemo"); DataTable dt = new DataTable("Student"); dt.Columns.Add("学号", typeof(string)); dt.Columns.Add("姓名", typeof(string)); dt.Columns.Add("性别", typeof(string)); dt.Columns.Add("年龄", typeof(Int16)); dt.Columns.Add("爱好", typeof(string)); dt.Rows.Add("1001","小羽","男",9,"跑步"); DataRow dr = dt.NewRow(); dr["学号"] = "2002"; dr["姓名"] = "小丽"; dr["性别"] = "女"; dr["年龄"] = 6; dr["爱好"] = "音乐"; dt.Rows.Add(dr); ds.Tables.Add(dt); ``` ### 属性 - `Columns`:获取属于该表的列的集合。 ```csharp string strColumns = ""; foreach (DataColumn dc in dt.Columns) { strColumns += dc.ColumnName + " "; } MessageBox.Show("学生表中共有 " + dt.Columns.Count.ToString() + " 列,分别为:\n\n" + strColumns); ``` - `DataSet`:获取此表所属的 `DataSet`。 ```csharp MessageBox.Show("学生表所属的 DataSet 名为:" + dt.DataSet.DataSetName); ``` - `DefaultView`:获取表的自定义视图。 ```csharp MessageBox.Show("点击“确定”将按年龄升序排序"); DataTable dt = wnGrid.DataSource; dt.DefaultView.Sort = "年龄 asc"; ``` - `PrimaryKey`:获取或设置数据表主键的列的数组。 ```csharp dt.PrimaryKey = new DataColumn[] { dt.Columns["学号"] }; ``` - `Rows`:获取属于该表的行的集合。 ```csharp MessageBox.Show("学生表中共有 " + dt.Rows.Count.ToString() + " 条记录"); ``` - `TableName`:获取或设置 `DataTable` 的名称。 ```csharp MessageBox.Show("学生表的 TableName 为:" + dt.TableName); ``` - `ExtendedProperties`:获取或设置用户自定义信息的集合。 ```csharp //ExtendedProperties扩展属性是PropertyCollection类型(Hashtable:键值对),故可以存放任何类型的数据 dt.ExtendedProperties["RowIndex"] = dt.Rows.Count == 0 ? -1 : 0; ``` ### 方法 - `AcceptChanges`:提交自加载以来或自上次调用 `AcceptChanges` 以来对该表进行的所有更改。 ```csharp dt.AcceptChanges(); ``` - `Clear`:清除所有行数据。 ```csharp dt.Clear(); ``` - `Clone`:复制 `DataTable` 的结构。 ```csharp DataTable dtClone = dt.Clone(); ``` - `Copy`:复制 `DataTable` 的结构和数据。 ```csharp DataTable dt1 = dt.Copy(); ``` - `Compute`:在符合过滤条件的行上执行给定表达式的计算,并返回计算结果。 ```csharp MessageBox.Show("计算学生的总年龄:\n\n公式:sum(年龄)\n\n过滤:1=1\n\n结果:" + dt.Compute("sum(年龄)", "1=1").ToString()); ``` - `GetChanges`:获取 `DataTable` 的副本,该副本包含自加载以来或自上次调用 `AcceptChanges` 以来对该数据集进行的所有更改。 ```csharp DataTable dt1 = dt.GetChanges(); dt1 = dt.GetChanges(DataRowState.Modified); //带筛选条件 ``` - `ImportRow`:将 `DataRow` 复制到 `DataTable` 中,保留原属性设置、初始值、当前值,以及行状态。 ```csharp DataTable dt1 = dt.Clone(); dt1.ImportRow(dt.Rows[0]); ``` - `NewRow`:创建与该表具有相同架构的 `DataRow` 对象。 ```csharp DataRow dr = dt.NewRow(); dr["学号"] = "5005"; dr["姓名"] = "小小"; dr["性别"] = "男"; dr["年龄"] = 8; dr["爱好"] = "游泳"; dt.Rows.Add(dr); ``` - `Select`:获取符合筛选条件的所有 `DataRow` 对象的数组。 ```csharp DataRow[] rows = dt.Select("年龄<9"); foreach (DataRow row in rows) { strInfo += row["姓名"].ToString() + ":" + row["年龄"].ToString() + " 岁\n\n"; } MessageBox.Show("通过 Select(参数) 方法\n\n按“年龄<9”过滤:\n\n" + strInfo); ``` ## 三、DataColumn对象 `DataColumn` 类型表示 `DataTable` 的一个单列。一般来说,一组 `DataColumn` 类型绑定到一个特定的 `DataTable`,组合成一个表的基本结构信息。 ```csharp //构建DataColumn时,常用的数据类型有:String、DateTime、Decimal、Int32、Boolean、Char DataTable dt = new DataTable("Product"); //添加DataColumn DataColumn spmc = new DataColumn("Spmc", typeof(String)); spmc.Caption = "商品名称"; DataColumn dj = new DataColumn("Dj", typeof(Int32)); dj.Caption = "单价"; DataColumn sl = new DataColumn("Sl", typeof(Int32)); sl.Caption = "数量"; DataColumn zj = new DataColumn("Zj", typeof(Int32)); zj.Caption = "总价"; dt.Columns.Add(spmc); dt.Columns.Add(dj); dt.Columns.Add(sl); dt.Columns.Add(zj); //添加DataRow DataRow dr1 = dt.NewRow(); dr1["Spmc"] = "足球"; dr1["Dj"] = 50; dr1["Sl"] = 11; dr1["Zj"] = 550; dt.Rows.Add(dr1); DataRow dr2 = dt.NewRow(); dr2["Spmc"] = "蓝球"; dr2["Dj"] = 10; dr2["Sl"] = 11; dr2["Zj"] = 110; dt.Rows.Add(dr2); ``` ### 属性 - `Caption`:获取或设置列的标题;如果没有设置,则为 `ColumnName` 的值。 ```csharp foreach (DataColumn dc in dt.Columns) { MessageBox.Show(dc.ColumnName + "的[Caption]为:" + dc.Caption); } ``` - `ColumnName`:获取或设置列的名称。 ```csharp foreach (DataColumn dc in dt.Columns) { MessageBox.Show(dc.Caption + "对应的[ColumnName]为:" + dc.ColumnName); } ``` - `DataType`:获取或设置列的数据类型。 ```csharp foreach (DataColumn dc in dt.Columns) { MessageBox.Show(dc.ColumnName + "对应的[DataType]为:" + dc.DataType.ToString()); } ``` - `DefaultValue`:获取或设置列的默认值。 ```csharp dt.Columns["Dj"].DefaultValue = 15; ``` - `MaxLength`:获取或设置文本列的最大长度。 ```csharp dt.Columns["Spmc"].MaxLength = 3; ``` - `Ordinal`:获取列在 `DataColumnCollection` 集合中的位置。 ```csharp foreach (DataColumn dc in dt.Columns) { MessageBox.Show(dc.ColumnName + "的[Ordinal]为:" + dc.Ordinal); } ``` - `Table`:获取列所属 `DataTable`。 ```csharp dt.Columns["Spmc"].Table.TableName ``` - `ExtendedProperties`:获取或设置用户自定义信息的集合。 ```csharp public class Product { public string spmc; public int sl; public int dj; public int zj; public Product(string spmc, int sl, int dj, int zj) { this.spmc = spmc; this.sl = sl; this.dj = dj; this.zj = zj; } } //设置属性值 Product product1 = new Product("篮球", 1, 30, 30); dt.Columns[0].ExtendedProperties["Spmc"] = product1; //获取属性值 Product product2 = dt.Columns[0].ExtendedProperties["Spmc"] as Product; MessageBox.Show("商品名称:" + product2.spmc + " 单价:" + product2.dj); ``` ### 方法 - `SetOrdinal`:将列的序号或位置更改为指定的序号或位置。 ```csharp MessageBox.Show("将[总价]的位置移至第一列"); dt.Columns["Zj"].SetOrdinal(0); ``` ## 四、DataRow对象 `DataColumn` 对象的集合用来表示 `DataTable` 的结构,而 `DataRow` 对象的集合表示的是表中的实际数据。 ```csharp DataTable dt = new DataTable("Student"); //添加列 dt.Columns.Add("学号", typeof(string)); dt.Columns.Add("姓名", typeof(string)); dt.Columns.Add("年龄", typeof(Int32)); //添加行 dt.Rows.Add("001", "张三", 21); dt.Rows.Add("002", "李四", 22); dt.Rows.Add("003", "王五", null); ``` ### 属性 - `ItemArray`:获取或设置存储在此行的所有值。 ```csharp DataRow dr = dt.Rows[0]; MessageBox.Show("ItemArray属性得到的行数据的值为:" + dr.ItemArray[0] + "," + dr.ItemArray[1]); ``` - `RowState`:获取该行的当前状态,共有5种状态,分别是:`Detached`、`Added`、`Unchanged`、`Modified`、`Deleted`。 ```csharp MessageBox.Show("演示从新增一行到删除此行过程中不同的行状态"); //Deteched状态 DataRow dr = dt.NewRow(); MessageBox.Show("调用NewRow()方法后行状态为:" + dr.RowState.ToString()); //Added状态 dr["学号"] = "005"; dr["姓名"] = "赵六"; dr["年龄"] = 23; dt.Rows.Add(dr); MessageBox.Show("调用Add()方法后行状态为:" + dr.RowState.ToString()); //Unchanged状态 dr.AcceptChanges(); //提交对dr的更改,如果不提交,在Added状态下修改此行,其状态仍为Added状态而不是Modified状态 MessageBox.Show("调用AcceptChanges()方法后行状态为:" + dr.RowState.ToString()); //Modified状态 dr["姓名"] = "赵六1"; MessageBox.Show("修改此行内容后行状态为:" + dr.RowState.ToString()); //Deleted状态 dr.Delete(); MessageBox.Show("调用Delete()方法后行状态为:" + dr.RowState.ToString()); //Deteched状态 dr.AcceptChanges(); MessageBox.Show("调用AcceptChanges()方法后行状态为:" + dr.RowState.ToString()); ``` - `Table`:获取该行所属 `DataTable`。 ```csharp MessageBox.Show("第一行DataRow对应的DataTable.TableName为:" + dt.Rows[0].Table.TableName); ``` ### 方法 - `AcceptChanges`:提交上次调用 `AcceptChanges` 以来对该行的所有更改。 ```csharp DataRow dr = dt.Rows[0]; dr.AcceptChanges(); ``` > **注意**: > > 当 `DataRow` 状态为 `Added` 和 `Modified` 时,调用 `AcceptChanges()` 方法状态变为 `Unchanged` 状态; > 当 `DataRow` 状态为 `Deleted` 时,调用 `AcceptChanges()` 方法状态变为 `Detached` 状态。 - `Delete`:删除 `DataRow` 对象。 ```csharp DataRow dr = dt.Rows[0]; dr.Delete(); ``` - `IsNull`:判断指定的 `DataColumn` 是否为空值。 ```csharp DataRow dr = dt.Rows[0]; dr.IsNull("姓名") ``` - `SetAdded`:将 `DataRow` 对象的 `RowState` 更改为Added。 ```csharp //用SetAdded()方法循环将dt中的行设置为Added状态 for (int i = 0; i < dt.Rows.Count; i++) { dt.Rows[i].SetAdded(); } MessageBox.Show("调用SetAdded()方法后的行状态为:\n\n" + dt.Rows[0].RowState + "," + dt.Rows[1].RowState + "," + dt.Rows[2].RowState); ``` - `SetModified`:将 `DataRow` 对象的 `RowState` 更改为 `Modified`。 ```csharp //用SetModified()方法循环将dt中的行设置为Modified状态 for (int i = 0; i < dt.Rows.Count; i++) { dt.Rows[i].SetModified(); } MessageBox.Show("调用SetModified()方法后的行状态为:\n\n" + dt.Rows[0].RowState + "," + dt.Rows[1].RowState + "," + dt.Rows[2].RowState); ``` > **扩展:** > > 1. 不同行状态的 `DataRow` 具有不同的行版本,行版本的类型有 `Original(原始值)`、`Current(当前值)`、`ProPosed(建议值)`和 `Default(默认值)`。 > > 2. 不同行状态 `DataRow` 所具有的行版本: > > `Detached`:行版本有 `ProPosed` 和 `Default` ,其中Default值为 `ProPosed` > > `Added`:行版本有 `Current` 和 `Default` ,其中Default值为 `Current` > > `Unchanged`:行版本有 `Original` 、`Current` 和 `Default`,其中Default值为 `Current` > > `Modified`:行版本有 `Original`、`Current` 和 `Default`,其中Default值为`Current` > > `Deleted`:行版本有 `Original` 和 `Default`,其中Default值为 `Original` ## 五、DataView对象 数据视图。`DataView` 可以用于对 `DataTable` 筛选,搜索,排序,编辑和导航。可以方便对 `DataTable` 的操作。 ```csharp DataTable dt = new DataTable("商品表"); DataColumn dc = dt.Columns.Add("商品编码", typeof(Int32)); dc.ReadOnly = true; dc.AutoIncrement = true; dc.AutoIncrementSeed = 1; dt.Columns.Add("商品名称", typeof(string)); dt.Columns.Add("商品价格", typeof(int)); dt.Columns.Add("商品产地", typeof(string)); dt.Columns.Add("商品生产商", typeof(string)); DataRow dr = dt.NewRow(); dr["商品名称"] = "足球"; dr["商品价格"] = 99; dr["商品产地"] = "山东"; dr["商品生产商"] = "鲁泰"; dt.Rows.Add(dr); DataRow dr1 = dt.NewRow(); dr1["商品名称"] = "足球"; dr1["商品价格"] = 88; dr1["商品产地"] = "山东"; dr1["商品生产商"] = "鲁泰"; dt.Rows.Add(dr1); dt.AcceptChanges(); //获取DataView视图 DataView dv = dt.DefaultView; ``` ### 属性 - `Count`:获取 `DataView` 中记录的个数。 ```csharp int count = dv.Count ``` - `RowFilter`:获取或设置 `DataView` 的条件过滤表达式。 ```csharp dv.RowFilter = "商品名称 like '%足球%'" ``` - `RowStateFilter`:获取或设置 `DataView` 的行状态过滤表达式。 > `Added`:新添加的行 > > `CurrentRows`:包括未更新的,新的和已修改的当前行 > > `Deleted`:已删除的行 > > `ModifiedOriginal`:已修改的数据的原始版本 > > `ModifiedCurrent`:已修改的原始数据的当前版本 > > `None`:无 > > `OriginalRows`:包括未更改行和已删除行的原始数据 > > `Unchanged`:未更改的行 ```csharp MessageBox.Show("将第一行[商品产地]列的值修改为“江苏”"); dt.Rows[0]["商品产地"] = "江苏"; dv.RowStateFilter = DataViewRowState.ModifiedOriginal; MessageBox.Show("第一行[商品产地]列修改前的值是“" + dv[0]["商品产地"] + "”"); dv.RowStateFilter = DataViewRowState.ModifiedCurrent; MessageBox.Show("第一行[商品产地]列修改后的值是“" + dv[0]["商品产地"] + "”"); ``` - `Sort`:获取或设置 `DataView` 的排序表达式。 ```csharp MessageBox.Show("按[商品名称]降序,[商品价格]升序排序"); dv.Sort = "商品名称 desc,商品价格 asc"; ``` - `Table`:获取或设置源 `DataTable`。 ```csharp MessageBox.Show("当前DataView对应的Table.TableName是:" + dv.Table.TableName) ``` ### 方法 - `Find`:按指定的排序关键字值在 `DataView` 中查找,返回符合条件的第一行的索引。 ```csharp MessageBox.Show("将 Sort 属性设为“商品名称,商品价格”,\n\n然后调用 Find(object[]) 方法"); dv.Sort = "商品名称,商品价格"; index = dv.Find(new object[] { "足球", "99" }); if (index == -1) { MessageBox.Show("没有找到[商品名称]是“足球”且[商品价格]是“99”的记录"); } else { MessageBox.Show("[商品名称]是“足球”且[商品价格]是“99”的\n\n第一条记录的索引值是: " + index); } ``` - `FindRows`:按指定的排序关键字值在 `DataView` 中查找,返回所有符合条件的 `DataRowView` 对象的数组。 ```csharp MessageBox.Show("先将 Sort 属性设为“商品名称”,\n\n然后调用 FindRows(object) 方法"); dv.Sort = "商品名称"; DataRowView[] drv = dv.FindRows("足球"); MessageBox.Show("[商品名称]是“足球”的记录数为:" + drv.Length); ``` - `ToTable`:根据现有 `DataView` 中的行,创建并返回一个新的 `DataTable`。 ```csharp DataTable dt = dv.ToTable("商品表_New", true, "商品名称", "商品产地"); MessageBox.Show("调用 ToTable(string tableName, bool distinct, params string[] columnNames) 方法得到的\n\n新表名称是:" + dt.TableName); ```