6.9 DataSet类

DataSet是非连接数据访问的核心,它包含两类最重要的元素:零个或者多个表的集合(通过DataTable属性提供。也就是说,DataSet.DataTable集合里的每一个项目是一个DataTable)以及零个或者多个关系的集合(通过Relations属性提供),关系可以把表联系在一起。

6.9.1 使用DataAdapter填充DataSet

其实,使用DataAdapter填充DataSet的方法与填充DataTable一样,你要做的就是创建一个新的空DataSet对象(在创建DataSet对象时,可以选择指定一个名称参数。如果没有为DataSet指定名称,则该名称会设置为“NewDataSet”),然后使用DataAdapter对象的Fill()方法来执行查询,并将查询的结果放到DataSet中新建的DataTable里。在Fill()方法中,可以指定表名,也可以不指定表名。如果不指定表名,系统会采用默认的表名。

下面的示例演示了如何使用DataAdapter来填充一个DataSet:


public DataSet GetEmployee()

{

string connectionString=

WebConfigurationManager.ConnectionStrings

["ConnectionString"].ConnectionString;

SqlConnection con=new SqlConnection(connectionString);

SqlDataAdapter adapter=new SqlDataAdapter(

"select*from Employee",con);

DataSet ds=new DataSet();

using(con)

{

adapter.Fill(ds);//或者adapter.Fill(ds,"Employee");

}

return ds;

}


填充好DataSet之后,就可以使用ds.Tables[0];或者ds.Tables["Employee"];的形式来获取DataSet里的DataTable来进行处理。如下面的代码所示:


protected void Page_Load(object sender, EventArgs e)

{

DataSet ds=GetEmployee();

DataTable myTable=ds.Tables[0];

//或者DataTable myTable=ds.Tables["Employee"];

foreach(DataColumn column in myTable.Columns)

{

Label1.Text+=column.ColumnName

+"      ";

}

Label1.Text+="RowState<br/>";

foreach(DataRow rows in myTable.Rows)

{

foreach(DataColumn column in myTable.Columns)

{

Label1.Text+=rows[column].ToString()

+"  ";

}

Label1.Text+=rows.RowState.ToString()+"<br>";

}

}


示例运行结果如图6-32所示。

6.9.2 使用多个表和关系

为了演示的需要,下面在数据库ASPNET4里添加一张工资表Salary。其中,Salary表与Employee表通过employeeid字段来建立关系。Salary表结构如图6-33所示。

figure_0242_0171

图 6-32 使用DataAdapter填充DataSet的示例运行结果

figure_0242_0172

图 6-33 数据库ASPNET4里的Salary表结构

下面的示例演示了如何从ASPNET4数据库里同时检索Salary表与Employee表以及如何在两表之间建立关联关系。

首先,需要使用DataAdapter将Salary表与Employee表填充到DataSet,如下面的代码所示:


public DataSet GetEmployee()

{

string connectionString=

WebConfigurationManager.ConnectionStrings

["ConnectionString"].ConnectionString;

string employeeSql="select*from Employee";

string salarySql="select*from Salary";

SqlConnection con=new SqlConnection(connectionString);

SqlDataAdapter adapter=new SqlDataAdapter(employeeSql, con);

DataSet ds=new DataSet();

using(con)

{

con.Open();

//将Employee表填充到DataSet

adapter.Fill(ds,"Employee");

//将Salary表填充到DataSet

adapter.SelectCommand.CommandText=salarySql;

adapter.Fill(ds,"Salary");

}

//将Salary与Employee通过employeeid来建立关系

DataRelation rel=new DataRelation("EmployeeSalary",

ds.Tables["Employee"].Columns["employeeid"],

ds.Tables["Salary"].Columns["employeeid"]);

ds.Relations.Add(rel);

return ds;

}


值得注意的是,在上面的代码中只创建一个DataAdapter对象来将两张表填充到了同一个DataSet中,这样的设计可以重用DataAdapter去更新数据源,从而避免了重复创建DataAdapter对象,提高程序的执行效率。并且,这里使用了显示打开连接的方式使整个操作完毕时才关闭连接,这尽可能地保证了最佳的性能。

表Salary与Employee的关系通过定义一个DataRelation对象并把它加入到DataSet.Relations集合来创建。创建DataRelation对象时,需要提供构造函数的三个参数:关系名称((EployeeSalary)、父表中作为主键的DataColumn(Employee的employeeid)与子表中作为外键的DataColumn(Salary的employeeid)。

对于这种关联关系,可以通过DataRow的GetChildRows()方法来获取相关的关联记录。如下面的代码所示:


DataRow[]childRows=row.GetChildRows("EmployeeSalary");


该方法在链接的DataTable中查找内存中的数据以查找匹配的记录,到相关的关联数据之后,就可以通过内嵌循环来查看它们了。示例如下面的代码所示:


protected void Page_Load(object sender, EventArgs e)

{

DataSet ds=GetEmployee();

StringBuilder str=new StringBuilder();

foreach(DataRow row in ds.Tables["Employee"].Rows)

{

str.Append("<b>");

str.Append(row["employeename"].ToString());

str.Append("</b><ul>");

//获取关联数据

DataRow[]childRows=row.GetChildRows("EmployeeSalary");

foreach(DataRow childRow in childRows)

{

str.Append("<li>");

str.Append("总工资:");

str.Append(childRow["total"].ToString());

str.Append("    应交税款:");

str.Append(childRow["salestax"].ToString());

str.Append("    实际工资:");

str.Append(childRow["salary"].ToString());

str.Append("</li>");

}

str.Append("</ul>");

}

Label1.Text=str.ToString();

}


示例运行结果如图6-34所示。

figure_0244_0173

图 6-34 示例运行结果

值得注意的是,在DataSet中添加一个关系之后,就会受到引用完整性的约束。例如,不能够删除一个有连接子行的父记录,同时也不能够创建一个引用不存在的父记录的子记录。这样,当DataSet只包含部分数据时就会产生一些问题。而解决这个问题的一个办法就是创建一个没有约束的DataRelation,使用DataRelation的一个接受createConstraints参数的构造函数就可以满足此要求,如下面的代码所示:


DataRelation rel=new DataRelation("EmployeeSalary",

ds.Tables["Employee"].Columns["employeeid"],

ds.Tables["Salary"].Columns["employeeid"],

false);


当然,也可以在添加关系前将DataSet的EnforceConstraints属性设置为false,从而禁止所有类型的约束检查,包括唯一性检查。