DataTable类
一、创建DataTable对象
前面已经学习了通过DataAdapter的Fill来生成DataTable对象,下面学习如何创建自己的DataTable对象,尤其是希望使用列级或表级限制来验证数据时。
1、创建DataTable对象
可以采用创建DataSet对象的相同方式来创建DataTable对象。DataTable拥有一个可选构造函数,可用来设置DataTable对象的TableName属性。
DataTable tb1 = new DataTable("学生");
Console.Write(tb1.TableName);
2、向DataSet中的Tables集合中添加DataTable
在创建DataTable之后,可以利用DataTableCollection类的Add方法,将其添加到已有的DataSet对象的Tables集合中。
DataSet ds = new DataSet();
DataTable tb1 = new DataTable("学生");
ds.Tables.Add(tb1);
ado.ne还提供了一个更为简便的方法,通过重载DataTableCollection类的Add方法,将一个新的DataTable添加到DataSet对象的Tables集合中。可以在单次调用中创建一个DataTable并将其添加到一个现有的DataSet的Tables集合中。
DataSet ds = new DataSet();
DataTable tb1 = ds.Tables.Add("学生");
可以通过检查DataTable对象的DataSet属性来确定一个DataTable是否存在于一个DataSet中。如果DataTable存在与一个DataSet对象的Tablese集合中,DataSet属性返回该DataSet。否则返回Nothing或Null,具体取决于所选择的语言。DataTable对象的DataSet属性是只读的。
还有一点值得注意的是:一个DataTable至多可以存在一个DataSet中。如果希望将一个DataTable添加到多个DataSet对象中,必须使用Copy或Clone方法。Copy方法是以相同结构创建一个新的DataTable,其中包含的数据行与原来的DataTable相同。Clone方法以相同的结构创建一个新的额DataTable对象,但不包括原数据行。
3、向DataTable中添加Column
为了存储查询结果,DataTable中需要一些列。
我们曾经用代码向DataSet对象的Tables集合中添加一个新的DataTable,通过利用几乎与此相同的代码可以向DataTable对象的Columns集合中添加DataColumn对象。
DataSet ds = new DataSet();
DataTable tb1 = ds.Tables.Add("学生");
DataColumn col1 = tb1.Columns.Add("姓名");
DataColumn col2=tb1.Columns.Add("性别");
4、为DataColumn指定数据类型。
可以用DataColumn的DataType属性来设置或检查列中的数据类型。
在向DataTable对象的Rows集合添加数据之前,DataColumn类的DataType属性是可读写的。
DataColumn col2=tb1.Columns.Add("年龄",typeof(int));
5、添加主键
PrimaryKey属性包含DataColumn对象的一个数组,所以不能简单地将这一属性设置为希望为主键值所使用的列的名称。
在所创建的DataTable对象中,一部分为单一列为主键值,而另一部分则以列的组合为主键。以下代码段包含了用于每一种情况的代码。Customers表使用单一列CostomerID,而Order Details表使用两个列的组合OrderID和ProductID。这两种情况必须创建一个DataColumn对象数组,并将该数组赋值给DataTable对象的PrimaryKey属性。
DataSet ds = new DataSet();
DataTable tb1;
tb1 = ds.Tables.Add("Customers");
tb1.Columns.Add("CustomerId", typeof(int));
tb1.PrimaryKey = new DataColumn[] { tb1.Columns["CustomerID"] };
DataTable tb2 = ds.Tables.Add("Order Dateils");
tb2.Columns.Add("OrderID",typeof(int));
tb2.Columns.Add("ProductID", typeof(int));
tb2.PrimaryKey = new DataColumn[] { tb2.Columns["OrderID"], tb2.Columns["ProductID"] };
6、添加其它约束
主键是应用最为广泛的约束,但也可以向DataTable中添加唯一键和外键约束。DataTable类的Constraints集合有一个重载的Add方法,可用于添加新的主键值,唯一键和外键约束。
可以将重载的Add方法划分为不同类别。ConstraintCollection类的Add方法接受任何继承自Constraint对象的对象,所以可以提供UniqueConstraint对象或ForeighnKeyConstraint对象。因此,可以执行如下所示的代码:
DataTable.Constraints.add(New UniqueConstraint(…));
DataTable.Constraints.add(New ForeignKeyConstraint(…));
首先,看一个使用Add方法创建唯一约束的例子,第一个参数包含新的唯一约束的名称,第二个参数包含构成唯一约束的DataColumn(或DataColumn的数组)。第三个参数是一个Boolean值,用来确定新的约束是否被用于DataTable的主键值。
DataSet ds = new DataSet();
DataTable tb1Customers = ds.Tables.Add("Customers");
tb1Customers.Columns.Add("CustomerID", typeof(string));
tb1Customers.Columns.Add("CompanyName"),typeof(string);
tb1Customers.Constraints.Add("PK_CustomerID",tb1Customers.Columns["CustomerID"],true);
tb1Customers.Constraints.Add("UK_CompanyName",tb1Customers.Columns["CompanyName"],true);
7、修改DataTable内容
(1)、添加新的DataRow
DataTable类拥有一个返回新的DataRow对象的NewRow方法,改对象包含表中每一列的相关信息。在创建了新DataRow之后,就可以使用其Item属性填充各列,还可以用Item属性查看行中列的内容。Item属性是DataRow类的默认属性,所以在使用Item时甚至不需要显示调用它。为了设置DataRow中一列的值,可提供该列的名称(或其索引或DataColumn本身),然后为其指定期望值。
DataTable的NewRow方法创建一个新行,但没有向DataTable中添加该行。
在为新行中所有的列提供了值,并为将其添加到DataTable准备就绪后,就可以使用DataRowCollection的Add方法,并提供新行。
DataSet ds = new DataSet();
DataTable tb1Customers = ds.Tables.Add("Customers");
tb1Customers.Columns.Add("CustomerID", typeof(string));
tb1Customers.Columns.Add("CompanyName",typeof(string));
tb1Customers.Constraints.Add("PK_CustomerID",tb1Customers.Columns["CustomerID"],true);
tb1Customers.Constraints.Add("UK_CompanyName",tb1Customers.Columns["CompanyName"],true);
DataRow row =tb1Customers.NewRow();
row["CustomerID"]="NEWCO";
row["CompanyName"] = "New Customer";
tb1Customers.Rows.Add(row);
DataRowCollection类的Add方法被重载,所以通过为新行提供列值清单而生成一个新的DataRow。其中RowState将被设置为Added。如下所示:
DataTable tb1 = new DataTable("Customers");
tb1.Columns.Add("CustomerID", typeof(string));
tb1.Columns.Add("CompanyName", typeof(string));
tb1.Rows.Add("NewCo", "New Cstomer");
DataTable类提供了第一种向表中添加数据的方法:LoadDataRow方法。此方法类似于被重载的Add方法,利用该方法可以为新的DataRow提供值清单,单它海让您控制新的DataRow的RowState,要使用这一方法,在第一个参数中提供一个数组。该数组中的项对应于表中的列。第二个参数AccepteChanges控制新DataRow的RowState属性,为这一参数传递False值,将会导致新行的RowState为Added,就象前面示例中的通过调用DataTable.NewRow和Rows.Add来添加行。
DataTable tb1 = new DataTable("Customers");
tb1.Columns.Add("CustomerID", typeof(string));
tb1.Columns.Add("CompanyName", typeof(string));
tb1.LoadDataRow(new object[] { "NEWCO", "New Customer" },false);
在通过调用DataAdapter对象的Update方法向数据库中提交更改时,DataAdapter查看每个DataRow的RowState,以确定如何更新数据库――――通过修改现有行、添加新行或删除现有行。如果向LoadDataRow中的第二个参数传递True值,新DataRow的RowState为UnChange,这意味着该行不能包括DataAdapter将提交给数据库的挂起更改。
8、修改现有行
在拥有一个DataRow对象之后,可以使用DataRow对象的Item属性来设定一个列的值,在前面已经了解如何使用这一属性来查看一列的值。这一属性是可读写的,所以海可以使用它来设置一列的值。下面的代码使用Rows集合的Find方法来查找Customers DataTable中的一行,然后改变CompanyName和ConstactName列的值。
DataTable tb1 = new DataTable("Customers");
tb1.Columns.Add("CustomerID", typeof(string));
tb1.Columns.Add("CompanyName", typeof(string));
tb1.PrimaryKey = new DataColumn[] {tb1.Columns["CustomerID"]};
tb1.LoadDataRow(new object[] { "NEWCO", "New Customer" }, false);
DataRow row = tb1.Rows.Find("NEWCO");
if (row == null)
{
Console.Write("没有这个客户");
}
else
{
Console.Write("找到这个客户了,现在在修改");
row["CompanyName"] = "new Value";
}
第二种方法与第一种类似,只是添加了对DataRow类BeginEdit方法和EndEdit方法的调用
DataTable tb1 = new DataTable("Customers");
tb1.Columns.Add("CustomerID", typeof(string));
tb1.Columns.Add("CompanyName", typeof(string));
tb1.PrimaryKey = new DataColumn[] {tb1.Columns["CustomerID"]};
tb1.LoadDataRow(new object[] { "NEWCO", "New Customer" }, false);
DataRow row = tb1.Rows.Find("NEWCO");
if (row == null)
{
Console.Write("没有这个客户");
}
else
{
Console.Write("找到这个客户了,现在在修改");
row.BeginEdit();
row["CompanyName"] = "new Value";
row.EndEdit();
}
使用BeginEdit和EndEdit可以对缓冲对数据行的更改,调用EndEdit保存对行的修改,如果确定不希望保存这些更改可以调用CancelEdit来撤销这些更改,该行将返回调用BeginEdit时的状态.
第三种方法
使用ItemArray属性。与Item属性类似,这一属性可用于获取或修改行的内容,这两个属性之间的不同在与Item属性每次处理一列,ItemArray属性返回和接受一个数组,其中每一项对应于一列。
如果希望在一行代码获取或修改多个行值,ItemArray属性非常方便。如果希望仅修改行中可用值的一个子集,清使用Null或Nothing(取决于所使用的语言)来指示不希望覆盖DataRow中的列的值。例如下面代码
DataTable tb1 = new DataTable("Customers");
tb1.Columns.Add("CustomerID", typeof(string));
tb1.Columns.Add("CompanyName", typeof(string));
tb1.PrimaryKey = new DataColumn[] {tb1.Columns["CustomerID"]};
tb1.LoadDataRow(new object[] { "NEWCO", "New Customer" }, false);
DataRow row = tb1.Rows.Find("NEWCO");
if (row == null)
{
Console.Write("没有这个客户");
}
else
{
row.ItemArray = new object[] { null, "New Value" };
}
8、处理DataRow中的Null值
DataRow类具有一个IsNull方法,可以用它来查看一个列是否包含Null值
9、删除DataRow
调用DataRow的Delete方法即可。
但是,删除数据行并没有将其从DataTable中移除,而是标记为挂起删除。
10、移除DataRow
如果确实希望DataTable移除一个数据行,而不是将其标记为挂起删除,可以使用DataRowCollection类的Remove或RemoveAt方法。如果拥有对一个欲删除的DataRow的引用,可以使用Remove方法。如果拥有该DataRow的索引号,则使用RemoveAt方法。
DataTable tb1 = new DataTable("Customers");
tb1.Columns.Add("CustomerID", typeof(string));
tb1.Columns.Add("CompanyName", typeof(string));
tb1.PrimaryKey = new DataColumn[] {tb1.Columns["CustomerID"]};
tb1.LoadDataRow(new object[] { "NEWCO", "New Customer" }, false);
DataRow row = tb1.Rows.Find("NEWCO");
if (row == null)
{
Console.Write("没有这个客户");
}
else
{
tb1.Rows.Remove(row);
//or
tb1.Rows.RemoveAt(tb1.Rows.IndexOf(row));
}
此外,DataSet和DataTable类各具有一个Clear方法,可以利用这一方法从DataSet或DataTable中删除全部DataRow对象,同时保留其结构。
11、使用DataRow.RowState属性
DataSet,DataTable和DataRow对象用作一种脱机处理数据缓存。可以查询数据库,并将结果存储在这些对象中。刚才已经了解到,可以添加、修改。和删除行。因为这些对象并没有连接到数据库,所以所做的变化将不会影响数据库中的内容。当然,如果不能在以后向数据库提交更改,那么脱机修改数据库的用途不是很大。
。net支持将更改返回数据库。在后面,将深入理解这一功能,对于目前来说,只介绍有关DataSet如何支持这一功能的一些基础知识。为了将更改缓存到DataRow,以便Ado.net可以在以后将这些更改提交给数据库,Ado.net必须记住已经对该行进行何种类型的变化。为什么?
更新数据库中所存储的数据的一种方法是执行以下查询
Insert into mytable (field1,field2,…. Fieldn) values(values1,values2,…valuesn)
或者
update Mytable set FieldToModify=NewValue where PKField=PkValue
或者
Delete from MyTable where PkField=PkValue
还可以通过存储过程,以类似方式进行更新。
关键在于,用于插入数据行的逻辑不同于用于修改数据行的逻辑,也不同于删除数据库的逻辑。因此,ADO.Net必须跟踪对DataRow进行了何种变化,以便在以后成功地将这些更改提交给数据库。
Ado.net将这些信息存储在DataRow中的一个RowState的属性中。可以使用DataRowState枚举中的值,来查看这一属性,可以确定该行数否已经被修改以及该行中所包含的更改类型(插入、修改、或删除)
常数 | 值 | 说明 |
Unchanged | 2 | 该行未包含任何挂起更改 |
Detached | 1 | 该行不是DataTable的一个成员 |
Added | 4 | 该行已经添加到DataTable中,但不存在于数据库中 |
Modified | 16 | 该行包含挂起更改 |
Deleted | 8 | 该行为挂起删除 |
12、控制DataRow的RowState
我们已经研究了各种操作如何影响DataRow的RowState,但如果希望更改RowState属性时应该怎么做呢?例如,您可能拥有一个DataRow,其RowState是Unchanged ,而您实际希望其