C#2008与.NET 3.5 高级程序设计读书笔记(23)-- ADO.NET之二:断开连接层
1、DataTable类
ADO.NET的DataTable类运行我们通过行和列的集合来查看数据。可以通过DataAdapter对象的Fill方法将查询结果存储在DataTable中:
conn = New SqlConnection("Data Source=(local);Initial Catalog=JWInfo;Integrated Security=True")
sqlCommand = New SqlCommand("SELECT * FROM 学生信息;", conn)
sqlAdapter = New SqlDataAdapter(sqlCommand)
dataSet = New DataSet()
sqlAdapter.Fill(dataSet, "学生信息")
在从数据库中读出数据并将其存储在DataTable对象之后,该数据即从服务器断开连接。然后就可以脱机查看DataTable对象的内容,而不会在ADO.NET和数据库之间产生任何网络通信流量。DataTable类包含了其他非连接对象的集合,例如可以通过DataTable的Rows属性访问其内容,这一操作将返回DataRow对象的一个集合。如果希望查看DataTable表的结构,则可以使用其Columns属性来获取DataColumn的对象集合。DataTable还允许为该类中存储的数据定义一些约束,如主键。可以通过DataTable对象的Constrains属性访问这些约束。
2、DataColumn类
每个DataTable都有一个DataColum的集合,该集合时DataColum对象的容器,从其名称可以看出,一个DataColumn对象对应于表中的一列,然而,DataColumn对象并非实际包含存储在DataTable中的数据,而是存储了有关该列的结构信息,例如数据类型,是否是只读的,是否允许存储Null值,是否是唯一的等等。
DataColumn类还包含一个Expression属性,用来指定如何计算列中的数据。通常我们会通过表达式来计算查询中一个列的值,例如:
SELECT OrderID, ProductID, Quantity, UnitPrice, Quantity*UnitPrice AS ItemTotal From [Order Details]
这样做的缺点是:数据库引擎只会在查询时执行计算。如果修改了DataTable对象中的UnitPrice或者Quantity列的内容,ItemTotal列不会发生任何变化。
ADO.NET的DataColumn类定义了一个Expression属性来完美地解决这个问题。当基于一个表达式来检查DataColumn对象的值时,ADO.NET会计算该表达式,并返回一个最新的值。这样,如果更新了表达式中任一列的值,存储在计算列中的值都是准确的。下面是具体的使用方法:
DataColumn col=new DataColumn();
col.ColumnName="ItemTotal";
col.DataType=typeof(Decimal);
col.Expression="UnitPrice * Quantity";
3、Constriant类
DataTable类还提供了一种方式,用于对DataTable对象中本地存储的数据设置约束。例如,可以建立一个Constraint对象,确保某一列或多列中的值在DataTable中式唯一的。Constraint对象存在于DataTable的Constraints集合中。
4、DataRow类
要想访问存储在DataTable对象中的实际值,可以使用此对象的Rows集合,该集合中包含一组DataRow对象。要想查看存储在特定行、特定列中的数据,可以使用对应DataRow对象的Item属性来读取该行中任意列的值。DataRow的Item属性有多个重载版本,可以通过指定列名称,索引值,甚至DataColumn对象来明确要查看哪一列。由于Item是DataRow的默认属性,因此可以隐式地使用它:
DataRow row;
row=tbl.Rows[0];
Console.WriteLine(row[0]);
Console.WriteLine(row["CustomerID"]);
Console.WriteLine(row[MyTable.Columns["CustomerID"]]);
可以通过调用DataRow对象的BeginEdit方法,通过Item属性修改此行中的一些列的值,然后通过EndEdit方法来讲更改保存到改行中。通过调用DataRow的CancelEdit方法,可以取消在当前编辑会话中所作的修改。
需要注意的是,在改变了一行的内容时,DataRow对象会缓存这些更改,从而可以在以后想数据库提交他们。
5、DataSet类
从其名称可以看出,DataSet对象包含一个数据集。可以将DataSet对象视为许多DataTable对象(它们存储在DataSet对象的DataTables集合中)的容器,也就是说相当于一个内存的数据库。ADO.NET的目的是帮助开发人员建立大型的多层数据库应用程序。有时,开发人员可能希望访问一个运行在中间层服务器上的组件,以获取许多表的内容。这时不必重复调用该服务器以便每次从一个表中获取数据,而是可以将所有的数据都装入一个DataSet对象中,并在一次单独调用中将其返回。但DataSet对象的功能绝不仅仅作为多个DataTable对象的容器。
存储在DataSet对象中的数据未与数据库连接。对数据所作的任何修改都将只是缓存在每个DataRow中。要将这些更改传递给数据库时,将整个DataSet对象回传给中间层服务器可能并非一种有效方法。可以使用GetChanges方法仅从DataSet中选出被修改的行。通过这样的方式,可以在不同进程或服务器之间传递较少的数据。
DataSet还公开了一个Merge方法,该方法可以作为GetChanges方法的一个补充。用于向数据库提交更改的中间层服务器(它使用的是由Merge方法返回的较小的DataSet)将会返回一个包含着新获得数据的DataSet。可以使用DataSet类的Merge方法来将两个DataSet对象的内容合并入一个DataSet中。
我们还可以在不建立与数据库连接的情况下,就是用信息填充DataSet对象的Tables表集合。在以前的数据库编程模型中,在本地添加新行之前,通常需要查询数据库,然后将它们提交给数据库。而使用ADO.NET,在准备好提交数据行之后,才需要与数据库通信。
6、DataRelation类
数据库中的表,通常以某种方式相关联。例如,在Northwind数据库中,Orders表中的每个项都与Customers表的一个表项相关联,因此可以确定哪位客户下了哪些订单。ADO.NET的DataRelation对象借助于DataRelation类来处理来自相关DataTable对象的数据。
DataTable类公开了一个Relations属性,该属性是DataRelation对象的一个集合。可以使用DataRelation对象来表示DataSet中不同DataTable对象之间的关系。
DataSet ds;
DataTable tblCustomers,tblOrders;
DataRelation rel;
//……创建并初始化DataSet
rel=ds.Relations.Add("Customers_Orders",tblCustomers.Columns["CustomerID"],tblOrders.Columns["CustomerID"]);
foreach(DataRow rowCustomer in tblCustomers.Rows)
{
Console.WriteLine(rowCustomer["CompanyName"]);
foreach(DataRow rowOrder in rowCustomer.GetChildRows(rel))
Console.WriteLine("{0}",rowOrder["OrderID"]);
Console.WriteLine();
}
7、DataView类
在将一查询结果置于DataTable对象中以后,就可以使用DataView对象以不同的方式来查看数据。如果希望根据某一列对DataTable对象的内容进行排序,只需要将DataView的Sort属性设置为该列的名称即可。还可以设置DataView的Filter属性,使得只有符合特定标准的行可见。
可以使用多个DataView对象同时查看同一个DataTable。例如在一个窗体中可以拥有两个表格,其中一个用于按照字母顺序显示所有客户,另一个则按照国家进行排序。为了显示所有视图,需要将每个表格绑定到不同的DataView对象。