第五课 使用断开数据--DataSet和SqlDataAdapter(翻译)

来源:互联网 发布:软件项目经理职责 编辑:程序博客网 时间:2024/05/14 08:52

本文档由李欣蔚(nirvana_li)翻译自http://www.csharp-station.com/,转载请注名出处!
更新日期2006-2-14

Lesson 05: Working with Disconnected Data - The DataSet and SqlDataAdapter

第五课:使用断开数据--DataSetSqlDataAdapter

这节课解释如何使用断开数据,使用DataSetSqlDataAdapter对象。这里这节课的目标:


  • 了解断开数据的需要
  • 获得对于DataSet用来做什么的基本了解
  • 学习如何使用SqlDataAdapter来找回和更新数据

介绍

在第三课中,我们讨论了使用Sqlcommand对象的与数据源的完全连接操作模型。在第四课,我们学习了如何通过连接使用SqlDataReader快速的读取数据。这节课介绍如何通过使用DataSetSqlDataAdapter来实现SqlConnectionSqlDataReader交互之间的事情。

DataSet是存储在内存中的数据,它保存了大量的表。DataSet只存储数据而并不与数据源发生交互。它通过SqlDataAdapter来管理与数据源的连接并给予我们非连接的行为。只有当需要的时候,SqlDataAdapter打开连接并在完成任务后关闭它。比如,当Data填充数据的时候SqlDataAdapter执行以下的操作:

1.           打开连接

2.           将数据读入到DataSet

3.           关闭连接

当更新DataSet时更新数据源,它执行以下的操作:

1.           打开连接

2.           DataSet中的改变写入数据源

3.           关闭数据源

FillUpdate操作中间的时间,数据源的连接是断开的,你能够随便的使用DataSet对数据进行读写。这些是使用断开数据的机制。因为只有当需要的时候应用程序才连接,这样应用程序才更加的可扩展。

一对场景描述了为什么你需要断开数据:人们使用网络连接并使web站点更加可扩展。考虑销售人员在旅行的时候需要客户数据。在最初的几天,他们将需要与主数据库同步以获得有效的最新信息。在这些天,它们将对已存在的用户数据进行修改,添加年用户,并且添加新的订单。这都是可以的,因为他们有相应的地区或者客户基础,而其它的用户不会改变相同的记录。在最后的几天中,销售人员将连接网络并把前晚上的改变的数据更新。

另一个场景是使web站点更加可扩展。使用SqlDataReader,你必须在显示每一页的时候返回数据库读取记录。则需要对每一次页面装载重新读取数据库,这将在用户数量增加的时候引起麻烦。消除这种情况的一种办法是使用DataSet,它只更新一次并缓存数据。每一个对页面的查询都会检测缓存并显示它。这避免的数据库的连接,使你的应用程序更加有效率。

上面的场景的异常包括你需要更新数据的情况。你必须抉择,基于你的场景中的数据如何被使用。当你的信息主要是读,则使用断开数据,但是当你需要更加动态的调用某些东西的时候,考虑其它的可选项(比如使用SqlCommand对象直接更新)。实际上,万事难料,但真正的指导方针应该是应用程序的需求,它将影响你的设计。

创建DataSet对象

实例化DataSet没有任何特别的内容,你应该创建一个新的实例,就像其它对象一样:

DataSet dsCustomers = new DataSet();

DataSet构造函数并不需要参数。然而当你将数据序列化为XML的时候为了得到DataSet的名字却有额外的负担。因为在这个例子中并不需要,我就不提了。现在数据集为空并且你需要SqlDataAdapter来装载它。

创建SqlDataAdapter

SqlDataAdapter使用SQL命令和连接对象来读写数据。对它进行初始化使用SQL选择语句和连接对象。

SqlDataAdapter daCustomers = new SqlDataAdapter(
    "select CustomerID, CompanyName from Customers", conn);

上面的代码创建了一个新的SqlDataAdapter对象daCustomers,SQLselect语句指明了将哪些数据读入数据集。连接对象conn应该已经被实例化,但不用打开。这是由SqlDataAdapter在调用FillUpdate方法的时候负责打开和关闭连接的。

正如早先指明的,SqlDataAdapter包含所有必需的与数据源交互的命令。代码显示了如何指定select语句,但是并没有显示insertupdatedelete语句。这些在初始化以后添加到SqlDataAdapter中。

这里有两种方式添加insertupdatedelete命令:通过SqlDataAdapter属性或者通过SqlCommandBuilder.在这节课,我将介绍使用SqlCommandBuilder的简单方式。在接下来的课程中,我将介绍如何使用SqlDataAdapter属性,它将需要更多的工作但是会带来比SqlCommandBuilder更大的能力。下面是如何使用SqlCommandBuilderSqlDataAdapter中添加命令:

SqlCommandBuilder cmdBldr = new SqlCommandBuilder(daCustomers);

注意上面的代码中SqlCommandBuilder是使用一个SqlDataAdapter对象daCustomers作为参数的构造函数实例化的。这说明SqlCommandBuilder对哪一个SalDataAdapter添加命令。SqlCommandBuilder将读取SQLselect语句(在SqlDataAdapter被实例化的时候指明),推断inser,updatedelete命令,并将新的命令分别赋值给SqlDataAdapterInsertUpdateDelete属性。

正如我先前所说,SqlCommandBuilder有限制性。它能在你对单独的表做简单的select语句的时候有效。然而,当需要连接两个以上的表或者必须执行一个存储过程的时候,它不会起作用。我将在以后的课程中描述这些场景的工作区。

填充DataSet

当具有一个DataSetSqlDataAdapter实例以后,你需要填充数据集。下面是如何实现它,只要使用SqlDataAdapterFill方法:

daCustomers.Fill(dsCustomers, "Customers");

上面代码中的Fill方法具有两个参数:DataSet对象和表名。DataSet必须在填充数据之前被实例化。第二个参数是将要在DataSet中创建的表的名字。你能够以你希望的任何名字对表命名。这要求能够用一个有意义的名字来标识表,以便以后使用。通常,我使用与数据库中表相同的名字来命名。然而,如果SqlDataAdapterselect命令包含多表连接,你将需要另外找一个有意义的名字。

Fill方法有另外一个重载的方式,它只接受DataSet一个参数。在这种情况中,对于第一个表的默认名字是“Table1。如果没有在Fill方法中指定名字,每一个添加到DataSet中的表名数字都将会自增(Table2Table3….TableN)。

使用DataSet

DataSet将能够与ASP.NETWindows FormsDataGrid控件相绑定。下面是将DataSet赋值给Windows FormsDataGrid控件的一个示例:

dgCustomers.DataSource = dsCustomers;
dgCustomers.DataMember = "Customers";

上面代码中我们做的第一件事情就是将DataSet赋值给DataGrid控件的DataSource属性。这让DataGrid知道它要绑定到那里,但是你将在GUI中得到一个’+’符号,因为DataSet能够保存多个表并且它允许你展开每一个有效的表。为了指定真正要使用哪个表,应该将DataGrid控件的DataMember属性设置为表的名字。在这个例子当中,我们设置为Customers,它与SqlDataAdapterFill方法中使用的第二个参数具有相同名字。这就是为什么我喜欢在Fill方法中指定表名字的原因,这样在后面的代码中就更具有可读性。

 

更新改变

在对数据做了修改以后,你将需要将改变写回给数据库。参考在这篇文章开始介绍的关于update的讨论,下面的代码展示了如何使用SqlDataAdapterUpdate方法将改变传回数据库。

daCustomers.Update(dsCustomers, "Customers");

上面的Update方法调用了最初填充dsCustomers数据集的SalDataAdapter实例。Update方法的第二个参数指定了从数据集中的哪个表来更新。这张表中包含一组被修改的记录,并且使用SqlDataAdapterInsertUpdateDelete属性包含的SQL语句来做数据库的修改。

整合

 

直到现在,你看到的代码片断需要实现断开数据管理。你真正需要的看看所有这些在一个应用程序如何实现。Listing1展示了从前面的代码断如何在程序中运作的,它已经简要的增强了本课的重点:

Listing 1: Implementing a Disconnected Data Management Strategy

using System;

using System.Data;

using System.Data.SqlClient;

using System.Drawing;

using System.Windows.Forms;

 

class DisconnectedDataForm : Form

{

        
private SqlConnection  conn;

        
private SqlDataAdapter daCustomers;

 

        
private DataSet  dsCustomers;

        
private DataGrid dgCustomers;

 

        
private const string TableName = "Customers";

 

        
// initialize form with DataGrid and Button

        
public DisconnectedDataForm()

        
{

               
// fill dataset

               InitData();

 

               
// set up datagrid

               dgCustomers 
= new DataGrid();

               dgCustomers.Location 
= new Point(55);

               dgCustomers.Size 
= new Size(
                       
this.ClientRectangle.Size.Width - 10,
                       
this.ClientRectangle.Height - 50);

               dgCustomers.DataSource 
= dsCustomers;

               dgCustomers.DataMember 
= TableName;

 

               
// create update button

               Button btnUpdate 
= new Button();

               btnUpdate.Text 
= "Update";

               btnUpdate.Location 
= new Point(

                       
this.ClientRectangle.Width/2 - btnUpdate.Width/2,

                       
this.ClientRectangle.Height - (btnUpdate.Height + 10));

               btnUpdate.Click 
+= new EventHandler(btnUpdateClicked);

 

               
// make sure controls appear on form

               Controls.AddRange(
new Control[] { dgCustomers, btnUpdate });

        }


 

        
// set up ADO.NET objects

        
public void InitData()

        
{

               
// instantiate the connection

               conn 
= new SqlConnection(
                       
"Server=(local);DataBase=Northwind;Integrated Security=SSPI");

              

               
// 1. instantiate a new DataSet

               dsCustomers 
= new DataSet();

 

               
// 2. init SqlDataAdapter with select command and connection

               daCustomers 
= new SqlDataAdapter(
                       
"select CustomerID, CompanyName from Customers", conn);

 

               
// 3. fill in insert, update, and delete commands

               SqlCommandBuilder cmdBldr 
= new SqlCommandBuilder(daCustomers);

              

               
// 4. fill the dataset

               daCustomers.Fill(dsCustomers, TableName);

        }


 

        
// Update button was clicked

        
public void btnUpdateClicked(object sender, EventArgs e)

        
{

               
// write changes back to DataBase

               daCustomers.Update(dsCustomers, TableName);

        }


 

        
// start the Windows Form

        
static void Main()

        
{

               Application.Run(
new DisconnectedDataForm());

        }


 }


Listing1中的InitData方法包含需要建立SqlDataAdapterDataSet的方法。注意不同数据对象是被定义在class级别的,这样它们能够在多个方法中使用,DataGridDataSource属性在构造函数中设置。无论用户在何时点击更新按钮,在btnupdateClicked事件中的Update方法都被调用,将修改后的数据返回给数据库。

总结

DataSet存有多张表,能够保存在内存中并能够重用。SqlDataAdapter使你能够填充DataSet并将更新返回给数据库。你不需要担心打开和关闭数据库的连接,因为SqlDataAdapter自动完成了。一个SqlComandBuilder基于SqlDataAdapterselect语句产生insert,updatedelete命令。使用SqlDataAdapterFill方法对DataSet填充数据集。调用SqlDataAdapterUpdate方法将改变返回给数据库。