博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

小菜之智能客户端(2)创建强类型DataSet

Posted on 2008-09-18 12:38  a-peng  阅读(3651)  评论(6编辑  收藏  举报

小菜打算先从微软的智能客户端案例:TaskVision开始,然后再分析IssueVision与FotoVision。

说起来真惭愧,TaskVision是在2002年发布,IssueVision和FotoVision是在2003年发布的,今年都2008快2009了,唉!小菜真是落后。不过没关系:先知耻而后勇!

本想这么多年过去了,小菜可参考的资源会比较多,不过可惜,可参考的资料并不多。

在网上看到Smart Client高级开发讲座:http://www.microsoft.com/china/msdn/events/featureevents/2004/SmartClientSeminar/index.aspx
本该非常开心,但反而让我更加伤心,因为很多不能下载,特别是最后一个:Smart Client 应用——Issuevision 案例分析 
看着这么好的标题,不能下载,想想都心疼。

现在唯一可参考的资料只有《C#企业级开发案例精解》一书和源码了。

好了废话不说了,开始我们的智能客户端TaskVision之旅吧。

这一篇主要讲述创建强类型DataSet,在TaskVision与IssueVision中都使用强类型DataSet。
强类型DataSet相比较非类型DataSet优点:方便,提供的支持多,可靠。
强类型DataSet相比较非类型DataSet缺点:有优点当然也就有缺点,对于强类型DataSet,如果数据库结构改变,我们需要重新生成xsd架构进而重新生成强类型DataSet。可见数据库结构与xsd架构的稳定对于强类型而言非常重要。

下面小菜会举例说明让你很清晰的感受到区别,所以这篇文章会比较长,大家先做好心理准备,不过保证是你在网上看不到的文章。

(一)、TaskVision数据库
TaskVision数据库名称:TaskVision,含有表Projects。

1、表Projects (存放项目的有关信息)

列名 数据类型 长度 允许空 描述
ProjectID int 4   项目表的主键,自动编号
ProjectName varchar 20   项目名称
ProjectDescription varchar 100   项目描述
IsDeleted bit 1   记录是否删除标记,默认值(0)
DateCreated datetime 8   项目创建日期,默认值(getdate())

表中已有内容:
image
对应本地应用程序界面:
image 
TaskVision使用的是强类型DataSet:表Projects对应DataSetProjects.xsd。

强类型DataSet在vs2002/vs2003与vs2005的差别比较大。
所以小菜先使用vs2003,然后再使用vs2005,这样大家的感触会比较深些。

(二)、使用vs2003创建XML架构,生成强类型DataSet
使用vs2003创建一个Asp.Net Web服务,添加新项:选择XML架构。(注意:不是数据集,下面会说到。)
XML架构就是XML Schema,文件扩展名为xsd。这些在第一篇讲过了。
不清楚可以返回第一篇:小菜之智能客户端(1)XML,DTD,XSD
image 
名称为:DataSetProjects.xsd
在服务器资源管理器中添加到TaskVision数据库的连接,打开DataSetProjects.xsd然后把Projects表拉入。
如下图:
image 
对应XML Schema代码如下:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema id="DataSetProjects" 
    targetNamespace
="http://tempuri.org/DataSetProjects.xsd" 
    elementFormDefault
="qualified"
    xmlns
="http://tempuri.org/DataSetProjects.xsd" 
    xmlns:mstns
="http://tempuri.org/DataSetProjects.xsd"
    xmlns:xs
="http://www.w3.org/2001/XMLSchema" 
    xmlns:msdata
="urn:schemas-microsoft-com:xml-msdata">
    
<xs:element name="Document" msdata:Locale="zh-CN">
        
<xs:complexType>
            
<xs:choice maxOccurs="unbounded">
                
<xs:element name="Projects">
                    
<xs:complexType>
                        
<xs:sequence>
                            
<xs:element name="ProjectID" msdata:ReadOnly="true" 
                                msdata:AutoIncrement
="true" type="xs:int" />
                            
<xs:element name="ProjectName" type="xs:string" />
                            
<xs:element name="ProjectDescription" type="xs:string" />
                            
<xs:element name="IsDeleted" type="xs:boolean" />
                            
<xs:element name="DateCreated" type="xs:dateTime" />
                        
</xs:sequence>
                    
</xs:complexType>
                
</xs:element>
            
</xs:choice>
        
</xs:complexType>
        
<xs:unique name="DocumentKey1" msdata:PrimaryKey="true">
            
<xs:selector xpath=".//mstns:Projects" />
            
<xs:field xpath="mstns:ProjectID" />
        
</xs:unique>
    
</xs:element>
</xs:schema>

补充:xs:unique为唯一性的约束,只要求数据必须是唯一的,但可以允许为空。
xs:key为键约束,要求比较严格,必须是唯一的,而且不允许空。
         不过在unique中指明了该约束为主键约束:msdata:PrimaryKey="true"也就是在架构中声明ProjectID为主键
         xs:selector的xpath属性,定位键所要应用到的数据表。
         xs:field的xpath属性,表示定位键所要应用的字段。         
         xs:element name="ProjectID" msdata:ReadOnly="true'为只读。msdata:AutoIncrement = "true"指明了为自增。指明自增默认种子为0,步长为1。即和数据库中的ProjectID一致。

其它XML Schema相关代码在第一篇中基本都说过了,不是很清楚的话可以返回第一篇:
1、我们不想显示IsDeleted字段,把它删掉。
(可以在视图中删除,也可以在代码中删除:<xs:element name="IsDeleted" type="xs:boolean" />
2、Document名称不直观,把它改成DataSetProjects。
(可以在视图中修改,也可以在代码中修改:<xs:element name="Document" msdata:Locale="zh-CN">改成<xs:element name="DataSetProjects" msdata:Locale="zh-CN">
3、将DataSetProjects属性IsDataSet设为true。
(可以在属性窗口中修改如下图:)
image
(也可以在代码中修改:<xs:element name="DataSetProjects" msdata:Locale="zh-CN">修改为<xs:element name="DataSetProjects" msdata:Locale="zh-CN" msdata:IsDataSet="true">

经过修改后视图如下图:
image
查看其XML源码如下:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema id="DataSetProjects" 
    targetNamespace
="http://tempuri.org/DataSetProjects.xsd" 
    elementFormDefault
="qualified"
    xmlns
="http://tempuri.org/DataSetProjects.xsd" 
    xmlns:mstns
="http://tempuri.org/DataSetProjects.xsd"
    xmlns:xs
="http://www.w3.org/2001/XMLSchema" 
    xmlns:msdata
="urn:schemas-microsoft-com:xml-msdata">
    
<xs:element name="DataSetProjects" msdata:Locale="zh-CN" msdata:IsDataSet="true">
        
<xs:complexType>
            
<xs:choice maxOccurs="unbounded">
                
<xs:element name="Projects">
                    
<xs:complexType>
                        
<xs:sequence>
                            
<xs:element name="ProjectID" msdata:ReadOnly="true" 
                                msdata:AutoIncrement
="true" type="xs:int" />
                            
<xs:element name="ProjectName" type="xs:string" />
                            
<xs:element name="ProjectDescription" type="xs:string" />
                            
<xs:element name="DateCreated" type="xs:dateTime" />
                        
</xs:sequence>
                    
</xs:complexType>
                
</xs:element>
            
</xs:choice>
        
</xs:complexType>
        
<xs:unique name="DocumentKey1" msdata:PrimaryKey="true">
            
<xs:selector xpath=".//mstns:Projects" />
            
<xs:field xpath="mstns:ProjectID" />
        
</xs:unique>
    
</xs:element>
</xs:schema>

在TaskVision的Web服务项目中的:DataService.asmx中我们可以看到如下Web方法。

[WebMethod(Description="Returns a project DataSet containing exactly one table named 'Projects'.")]
public DataSetProjects GetProjects()
{
    DataSetProjects ds 
= new DataSetProjects();
    daProjects.Fill(ds, 
"Projects");

    
return ds;
}

小菜将关于客户端用户验证的代码去掉,之后会专门来说客户端用户验证这一块。

关键看DataSetProjects ds = new DataSetProjects();这一行代码。
DataSetProjects 是什么呢?它是强类型DataSet。上面的代码就像DataSet ds = new DataSet();不过DataSet是非类型。

在我们的程序中没有DataSetProjects这个类啊?我们如何使用上面的代码啊?
我们可以利用之前创建的DataSetProjects.xsd这个XML架构来生成强类型的DataSet:DataSetProjects
怎么创建呢?很简单动下你的鼠标就行了。
打开DataSetProjects.xsd,鼠标右键,单击生成数据集。
image
就会生成:DataSetProjects.cs文件(当然你要选择显示所有文件,不然你怎么看到),查看代码如下:

public class DataSetProjects : DataSet {}

这样我们就得到了强类型DataSet:DataSetProjects了。
选择DataSetProjects.xsd属性
image 
你会看到自定义工具:MSDataSetGenerator,其实生成数据集就是使用它。

接下来我们就来使用下它吧!
Web服务Service1.asmx中添加Web方法:GetProjects()

using System;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.Services;

namespace WebService1
{
    
/// <summary>
    
/// Service1 的摘要说明。
    
/// </summary>

    public class Service1 : System.Web.Services.WebService
    
{
        
private SqlConnection _conn;
        
private SqlDataAdapter _daProjects;
        
private SqlCommand _selectCommand;

        
public Service1()
        
{
           
//CODEGEN: 该调用是 ASP.NET Web 服务设计器所必需的
            InitializeComponent();
        }


        
组件设计器生成的代码

        [WebMethod(Description
="Returns a project DataSet containing exactly one table named 'Projects'.")]
        
public DataSetProjects GetProjects()
        
{
            DataSetProjects ds 
= new DataSetProjects();
            _daProjects.Fill(ds, 
"Projects");
    
            
return ds;
        }

    }

}

运行我们可以对Web服务Service1.asmx中的Web方法:GetProjects进行调用测试:
image
调用将输出一个XML,代码如下:
返回的是强类型DataSet:DataSetProjects怎么为变成XML呢?
Web服务是以XML为基础,传输都是使用标准的XML,所以Web服务会将传输的对象序列化为XML,DataSetProjects继承DataSet,DataSet是可序列化的所以DataSetProjects也是可序列化的。程序引用Web服务,Web服务代理接收到XML文件会自动反序列为原来的对象方便调用,使你感觉不到调用Web服务与调用其它函数有什么不同之处。
<?xml version="1.0" encoding="utf-8"?>
<DataSetProjects xmlns="http://tempuri.org/">
  
<xs:schema id="DataSetProjects" 
    targetNamespace
="http://tempuri.org/DataSetProjects.xsd" 
    xmlns:mstns
="http://tempuri.org/DataSetProjects.xsd" 
    xmlns
="http://tempuri.org/DataSetProjects.xsd" 
    xmlns:xs
="http://www.w3.org/2001/XMLSchema" 
    xmlns:msdata
="urn:schemas-microsoft-com:xml-msdata" 
    attributeFormDefault
="qualified" 
    elementFormDefault
="qualified">
    
<xs:element name="DataSetProjects" 
        msdata:IsDataSet
="true" msdata:Locale="zh-CN">
      
<xs:complexType>
        
<xs:choice minOccurs="0" maxOccurs="unbounded">
          
<xs:element name="Projects">
            
<xs:complexType>
              
<xs:sequence>
                
<xs:element name="ProjectID" 
                    msdata:ReadOnly
="true" msdata:AutoIncrement="true" type="xs:int" />
                
<xs:element name="ProjectName" type="xs:string" />
                
<xs:element name="ProjectDescription" type="xs:string" />
                
<xs:element name="DateCreated" type="xs:dateTime" />
              
</xs:sequence>
            
</xs:complexType>
          
</xs:element>
        
</xs:choice>
      
</xs:complexType>
      
<xs:unique name="DocumentKey1" msdata:PrimaryKey="true">
        
<xs:selector xpath=".//mstns:Projects" />
        
<xs:field xpath="mstns:ProjectID" />
      
</xs:unique>
    
</xs:element>
  
</xs:schema>
  
<diffgr:diffgram 
    
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" 
    xmlns:diffgr
="urn:schemas-microsoft-com:xml-diffgram-v1">
    
<DataSetProjects xmlns="http://tempuri.org/DataSetProjects.xsd">
      
<Projects diffgr:id="Projects1" msdata:rowOrder="0">
        
<ProjectID>1</ProjectID>
        
<ProjectName>Acme</ProjectName>
        
<ProjectDescription>This is a test project.</ProjectDescription>
        
<DateCreated>2003-01-02T06:29:05.42+08:00</DateCreated>
      
</Projects>
      
<Projects diffgr:id="Projects2" msdata:rowOrder="1">
        
<ProjectID>2</ProjectID>
        
<ProjectName>Microsoft</ProjectName>
        
<ProjectDescription>This is a test project.</ProjectDescription>
        
<DateCreated>2003-01-02T06:29:05.513+08:00</DateCreated>
      
</Projects>
    
</DataSetProjects>
  
</diffgr:diffgram>
</DataSetProjects>
针对这个例子我们来说说强类型DataSet与非DataSet的区别:我们需要取得表Projects第一行记录ProjectName的值。
针对非类型DataSet:
[WebMethod]
public string GetProjectName()
{
    DataSet ds 
= new DataSet();
    _daProjects.Fill(ds,
"Projects");

    
return ds.Tables["Projects"].Rows[0]["ProjectName"].ToString();            
}
调用该Web方法返回:
<?xml version="1.0" encoding="utf-8" ?>
<string xmlns="http://tempuri.org/">Acme</string> 
从上面可以看出非类型DataSet:ds.Tables["Projects"].Rows[0]["ProjectName"]返回的是object类型。我们需要强转换。
我们需要拼写正确的字段名,如果把ProjectName拼写成ProjectNane的话,我们需要在运行时才会提示错误。

针对强类型DataSet:
[WebMethod]
public string GetProjectName()
{
    DataSetProjects ds 
= new DataSetProjects();
    _daProjects.Fill(ds, 
"Projects");
    
    
return ds.Projects[0].ProjectName;       
}
调用该Web方法返回和上面一样的结果。
ds.Projects[0].ProjectName;返回类型直接就是ProjectName的类型string,无需我们强转换。ProjectName如果我们拼写成ProjectNane那么编译就会产生错误。

我们来使用DataTable的Find方法来实现GetProjectName可以更清晰的看出区别:
针对非类型DataSet:
[WebMethod]
public string GetProjectName()
{
  DataSet ds 
= new DataSet();
  _daProjects.Fill(ds,
"Projects");

  DataTable tbl 
= ds.Tables["Projects"];
  tbl.PrimaryKey 
= new DataColumn[]{tbl.Columns["ProjectID"]};//定义主键

  DataRow row 
= tbl.Rows.Find(1);//ProjectID=1

  
return row["ProjectName"].ToString();
要想使用DataTable的Find方法必须定义主键。
针对强类型由于xsd中已经定义好了主键,所以无需我们在程序中定义而且还有更清晰的方法:
[WebMethod]
public string GetProjectName()
{
  DataSetProjects ds 
= new DataSetProjects();
  _daProjects.Fill(ds, 
"Projects");

  
return ds.Projects.FindByProjectID(1).ProjectName;//ProjectID=1
}
从上面的两个例子可以看出强类型DataSet给我们带来非常大的方便。
强类型对应的方法和属性都可以在DataSetProjects.cs文件中找到。class DataSetProjects类中
比如上面用到的方法:
public ProjectsRow FindByProjectID(int ProjectID) {
  
return ((ProjectsRow)(this.Rows.Find(new object[] {
                            ProjectID}
)));
}
所以你也可以看到,其实就是把非类型的DataSet的操作进行封装。

(三)使用vs2003创建数据集,生成强类型DataSet 
使用vs2003创建一个Asp.Net Web服务,添加新项:选择数据集:名称DataSetProjects.xsd
小菜上面说过一句话:添加新项:选择XML架构(注意不是数据集,下面会讲到)现在就讲到了。
和之前的一样,添加到TaskVision数据库的连接,打开DataSetProjects.xsd然后把Projects表拉入。
直接就得到下图:
image
我们不需要显示:IsDeleted,把其删除。
显示所有文件,我们会看到,我们已经有了一个:DataSetProjects.cs查看代码如下:
public class DataSetProjects : DataSet {}

噢,苍天啊大地啊,这么方便!(其实就是vs2003帮你做了之前你所做的那些事。)
如果一开始就和你讲这么简单的实现的话,那么你一定没有心思看上面那么复杂的创建过程(其实一点也不复杂)。而且直接和你说下面一种方式,你什么也没学到,只是学到添加新项,选择数据集,而已,仅此而已。
至于为什么要说上面那个复杂的过程,因为在vs2005里,可没有这么便宜的事。连上面那个复杂的过程你也别想有。不信啊,你就接着往下看,

(四)、使用vs2005 XML架构生成强类型DataSet
接下来进入你的痛苦旅程:在vs2005中实现和上述同样的功能。
上面的实现就是TaskVision中的实现,不过毕竟TaskVision是在vs2002中创建的,我们的最终目的,当然是移植到vs2005,并且利用vs2005的特性。

在vs2005中创建一个Asp.Net Web服务
添加新项,同样是选择XML架构,而不是数据集。(同样至于为何,下面会讲到。)
添加到TaskVision数据库的连接,打开DataSetProjects.xsd然后把Projects表拉入。
如下图所示:
image
和在vs2003中生成的一样,不过方向倒了,颜色换了而已,脱了马甲,我们还是认得它。
1、我们不想显示IsDeleted,把它删掉。
2、Document名称不直观,把它改成DataSetProjects
3、将DataSetProjects属性IsDataSet设为true。(很遗憾的告诉你,没有这个属性,虽然在vs2003中有这个东西,可是vs2005中没有。)
怎么办呢?我们可以比较下这次的XML代码和之前使用vs2003中生成的XML代码的区别就可以很快找到答案。
vs2003中:<xs:element name="DataSetProjects" msdata:IsDataSet="true" msdata:Locale="zh-CN">
vs2005中:  <xs:element name="DataSetProjects">
所以呢!!!加上msdata:IsDataSet="true"吧。
重新打开DataSetProjects.xsd如下图:
image
接下来使用这个XML Schema来生成强类型DataSet:DataSetProjects。
在vs2003中多方便啊,小菜至今还在回味,右键,生成数据集,在vs2005中也试一下吧。
右键如下图:
image 
噢,生成数据集的按钮跑哪去了呢?怎么办啊,急死我了。(很遗憾的告诉你,没有。)
那怎么办呢?难道就这样放弃?不行,小菜可不轻言放弃。
小菜记起,在上面vs2003中生成数据集的时候。可以使用自定义工具:MSDataSetGenerator,来生成数据集。
点击DataSetProjects.xsd属性如下图:
image
怎么自定义工具也没有了,唉,微软vs2005,你有必要这么绝情吗?(注意了,其实Windows项目中属性有自定义工具,你输入MSDataGenerator就可以生成DataSetProjects.cs文件了,不过在Asp.Net Web服务和Asp.Net站点中属性中是没有自定工具这个选项的)

不过:上有政策,下有对策。
我们可以使用xsd.exe来生成DataSetProjects.cs文件。
xsd.exe在哪呢?你可以使用windows搜索一下。小菜的电脑上装有vs2003和vs2005所以有两个。
D:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin\xsd.exe(vs2003中的v1.1)
D:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\xsd.exe(vs2005中的v2.0)

注意了,小菜不是让你运行它们,不过运行也没事,反正你也运行不了。:)
开始-》所有程序-》Microsoft .NET Framework SDK v2.0-》SDK命令提示
输入命令:xsd /dataset /language:cs "DataSetProjects.xsd的路径" /o:"DataSetProjects.cs输出的路径"
如下图:
 image
成功生成了DataSetProjects.cs文件了,如下图:
 image
查看DataSetProjects.cs代码:

public partial class DataSetProjects : System.Data.DataSet {}

我们成功得到了强类型DataSet:DataSetProjects
接下来同样在我们的Web服务中使用DataSetProjects

using System;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace 
= "http://tempuri.org/")]
[WebServiceBinding(ConformsTo 
= WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
    
private SqlConnection _conn;
    
private SqlDataAdapter _daProjects;
    
private SqlCommand _selectCommand;

    
public Service () {

        
//如果使用设计的组件,请取消注释以下行 
        
//InitializeComponent(); 

        _conn 
= new SqlConnection("Data Source=(local);Initial Catalog=TaskVision;User ID=sa;Password=password;");
        _daProjects 
= new SqlDataAdapter();

        _selectCommand 
= new SqlCommand();
        _selectCommand.Connection 
= _conn;
        _selectCommand.CommandText 
= "SELECT ProjectID, ProjectName, ProjectDescription, DateCreated FROM Projects WHERE (IsDeleted = 0)";

        _daProjects.SelectCommand 
= _selectCommand;
    }


    [WebMethod]
    
public string HelloWorld() {
        
return "Hello World";
    }


    [WebMethod(Description 
= "Returns a project DataSet containing exactly one table named 'Projects'.")]
    
public DataSetProjects GetProjects()
    
{
        DataSetProjects ds 
= new DataSetProjects();
        _daProjects.Fill(ds, 
"Projects");

        
return ds;
    }

}

运行一下,噢,错误    1    找不到类型或命名空间名称“DataSetProjects”(是否缺少 using 指令或程序集引用?)   
傻瓜错误,不过确有很多人犯,把DataSetProjects.cs放入App_Code文件夹中。就可以了。
所以在之前的生成命令中,我们可以直接指定DataSetProjects.cs输出到App_Code文件夹下,我们就省了麻烦。

好成功了!

我想到这里你还没有感觉到强类型DataSet的缺点吧!现在就让你感受一下吧。
还记得在(二)中使用的如下代码吗
[WebMethod]
public string GetProjectName()
{
  DataSetProjects ds 
= new DataSetProjects();
  _daProjects.Fill(ds, 
"Projects");

  
return ds.Projects.FindByProjectID(1).ProjectName;//ProjectID=1
}
量是在这里无效会出现错误,提示错误,找不到主键,之前已经说过了使用Find方法必须具有主键。
但这里为什么没有主键呢?我们可以查看DataSetProjects.xsd的XML代码。
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="DataSetProjects"
    targetNamespace
="http://tempuri.org/XMLSchema.xsd"
    elementFormDefault
="qualified"
    xmlns
="http://tempuri.org/XMLSchema.xsd"
    xmlns:mstns
="http://tempuri.org/XMLSchema.xsd"
    xmlns:xs
="http://www.w3.org/2001/XMLSchema"
    xmlns:msdata
="urn:schemas-microsoft-com:xml-msdata">
  
<xs:element name="DataSetProjects" msdata:IsDataSet="true">
    
<xs:complexType>
      
<xs:choice minOccurs="0" maxOccurs="unbounded">
        
<xs:element name="Projects">
          
<xs:complexType>
            
<xs:sequence>
              
<xs:element name="ProjectID" type="xs:int" />
              
<xs:element name="ProjectName" type="xs:string" />
              
<xs:element name="ProjectDescription" type="xs:string" />
              
<xs:element name="DateCreated" type="xs:dateTime" />
            
</xs:sequence>
          
</xs:complexType>
        
</xs:element>
      
</xs:choice>
    
</xs:complexType>
    
<xs:unique name="DocumentKey1">
      
<xs:selector xpath=".//mstns:Projects" />
      
<xs:field xpath="mstns:ProjectID" />
    
</xs:unique>
  
</xs:element>
</xs:schema>
在上面的XML代码中,我们只看到了为ProjectID定义的唯一性约束,而没有为其定义主键PrimaryKey。
所以vs2005与vs2003自动产生的代码是不一样的。让我们对其修改代码如下:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="DataSetProjects"
    targetNamespace
="http://tempuri.org/DataSetProjects.xsd"
    xmlns:mstns
="http://tempuri.org/DataSetProjects.xsd"
    xmlns
="http://tempuri.org/DataSetProjects.xsd"
    xmlns:xs
="http://www.w3.org/2001/XMLSchema"
    xmlns:msdata
="urn:schemas-microsoft-com:xml-msdata"
    attributeFormDefault
="qualified"
    elementFormDefault
="qualified">
  
<xs:element name="DataSetProjects" msdata:IsDataSet="true" msdata:Locale="en-US">
    
<xs:complexType>
      
<xs:choice minOccurs="0" maxOccurs="unbounded">
        
<xs:element name="Projects">
          
<xs:complexType>
            
<xs:sequence>
              
<xs:element name="ProjectID" msdata:ReadOnly="true"
                    msdata:AutoIncrement
="true" type="xs:int" />
              
<xs:element name="ProjectName" type="xs:string" />
              
<xs:element name="ProjectDescription" type="xs:string" />
              
<xs:element name="DateCreated" type="xs:dateTime" />
            
</xs:sequence>
          
</xs:complexType>
        
</xs:element>
      
</xs:choice>
    
</xs:complexType>
    
<xs:unique name="DataSetProjectsKey1" msdata:PrimaryKey="true">
      
<xs:selector xpath=".//mstns:Projects" />
      
<xs:field xpath="mstns:ProjectID" />
    
</xs:unique>
  
</xs:element>
</xs:schema>
现在XML架构改变了,我们需要使用xsd.exe重新生成强类型DataSet:DataSetProjects。
如果你已经在本地应用程序引用了Web服务,使用该强类型DataSet:DataSetProjects,则需要更新Web服务的引用。可见XML架构的稳定对强类型DataSet来说非常重要,否则上面的重复过程也够你烦的。

(五)、使用vs2005 数据集生成强类型DataSet
vs2005提供的数据集功能非常的强大,特别是TableAdapter。
不过有正就有反,功能强大了,附加的代码也就多了,微软自动生成的代码目标当然是最通用的代码,而不是最适合你的代码。所以小菜现在还是比较倾向(四)、使用vs2005 XML架构生成强类型DataSet。

不过了解一下还是有必要的,这样才能更好的对比。而且自动生成的代码也可以参考。

同样在vs2005中创建一个Asp.Net Web服务。
1、添加数据集:DataSetProjects.xsd
2、会弹出TableAdapter配置向导让你选择数据库连接,直接取消。因为下面当我们直接拉入Projects表的时候就会自动生成。
3、把表Projects拉入,如下图
image 
删除IsDeleted。
vs2005默认帮我们创建了ProjectsTableAdapter,而且这是个功能最全的ProjectsTableAdapter,因为微软认为应该给你提供最完整的功能。
接下来我们就来使用一下吧。
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace 
= "http://tempuri.org/")]
[WebServiceBinding(ConformsTo 
= WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
    
public Service () {

        
//如果使用设计的组件,请取消注释以下行 
        
//InitializeComponent(); 
    }


    [WebMethod]
    
public string HelloWorld() {
        
return "Hello World";
    }


    [WebMethod(Description 
= "Returns a project DataSet containing exactly one table named 'Projects'.")]
    
public DataSetProjects GetProjects()
    
{
        DataSetProjects ds 
= new DataSetProjects();

        DataSetProjectsTableAdapters.ProjectsTableAdapter adapter 
= new DataSetProjectsTableAdapters.ProjectsTableAdapter();
        adapter.Fill(ds.Projects);

        
return ds;
    }

}

不要惊慌,你看到的代码是真的。我们做了些什么,我们什么也没做。VS2005帮你都做了。
别人帮你做的太多了,会让我有点无所适从,因为我不清楚别人帮我做了些什么,怎么办呢?看看源码啊!
所有的代码都在DataSetProjects.xsd中:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="DataSetProjects" targetNamespace="http://tempuri.org/DataSetProjects.xsd" xmlns:mstns="http://tempuri.org/DataSetProjects.xsd" xmlns="http://tempuri.org/DataSetProjects.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:msprop="urn:schemas-microsoft-com:xml-msprop" attributeFormDefault="qualified" elementFormDefault="qualified">
  
<xs:annotation>
    
<xs:appinfo source="urn:schemas-microsoft-com:xml-msdatasource">
      
<DataSource DefaultConnectionIndex="0" FunctionsComponentName="QueriesTableAdapter" Modifier="AutoLayout, AnsiClass, Class, Public" SchemaSerializationMode="IncludeSchema" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
        
<Connections>
          
<Connection AppSettingsObjectName="Web.config" AppSettingsPropertyName="TaskVisionConnectionString" ConnectionStringObject="" IsAppSettingsProperty="True" Modifier="Assembly" Name="TaskVisionConnectionString (Web.config)" ParameterPrefix="@" PropertyReference="AppConfig.System.Configuration.ConfigurationManager.0.ConnectionStrings.TaskVisionConnectionString.ConnectionString" Provider="System.Data.SqlClient">
          
</Connection>
        
</Connections>
        
<Tables>
          
<TableAdapter BaseClass="System.ComponentModel.Component" DataAccessorModifier="AutoLayout, AnsiClass, Class, Public" DataAccessorName="ProjectsTableAdapter" GeneratorDataComponentClassName="ProjectsTableAdapter" Name="Projects" UserDataComponentName="ProjectsTableAdapter">
            
<MainSource>
              
<DbSource ConnectionRef="TaskVisionConnectionString (Web.config)" DbObjectName="TaskVision.dbo.Projects" DbObjectType="Table" FillMethodModifier="Public" FillMethodName="Fill" GenerateMethods="Both" GenerateShortCommands="True" GeneratorGetMethodName="GetData" GeneratorSourceName="Fill" GetMethodModifier="Public" GetMethodName="GetData" QueryType="Rowset" ScalarCallRetval="System.Object, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" UseOptimisticConcurrency="True" UserGetMethodName="GetData" UserSourceName="Fill">
                
<DeleteCommand>
                  
<DbCommand CommandType="Text" ModifiedByUser="False">
                    
<CommandText>DELETE FROM [Projects] WHERE (([ProjectID] = @Original_ProjectID) AND ([ProjectName] = @Original_ProjectName) AND ([ProjectDescription] = @Original_ProjectDescription) AND ([DateCreated] = @Original_DateCreated))</CommandText>
                    
<Parameters>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="Int32" Direction="Input" ParameterName="@Original_ProjectID" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="ProjectID" SourceColumnNullMapping="False" SourceVersion="Original">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@Original_ProjectName" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="ProjectName" SourceColumnNullMapping="False" SourceVersion="Original">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@Original_ProjectDescription" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="ProjectDescription" SourceColumnNullMapping="False" SourceVersion="Original">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="DateTime" Direction="Input" ParameterName="@Original_DateCreated" Precision="0" ProviderType="DateTime" Scale="0" Size="0" SourceColumn="DateCreated" SourceColumnNullMapping="False" SourceVersion="Original">
                      
</Parameter>
                    
</Parameters>
                  
</DbCommand>
                
</DeleteCommand>
                
<InsertCommand>
                  
<DbCommand CommandType="Text" ModifiedByUser="False">
                    
<CommandText>INSERT INTO [Projects] ([ProjectName], [ProjectDescription], [DateCreated]) VALUES (@ProjectName, @ProjectDescription, @DateCreated);
SELECT ProjectID, ProjectName, ProjectDescription, DateCreated FROM Projects WHERE (ProjectID = SCOPE_IDENTITY())
</CommandText>
                    
<Parameters>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@ProjectName" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="ProjectName" SourceColumnNullMapping="False" SourceVersion="Current">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@ProjectDescription" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="ProjectDescription" SourceColumnNullMapping="False" SourceVersion="Current">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="DateTime" Direction="Input" ParameterName="@DateCreated" Precision="0" ProviderType="DateTime" Scale="0" Size="0" SourceColumn="DateCreated" SourceColumnNullMapping="False" SourceVersion="Current">
                      
</Parameter>
                    
</Parameters>
                  
</DbCommand>
                
</InsertCommand>
                
<SelectCommand>
                  
<DbCommand CommandType="Text" ModifiedByUser="False">
                    
<CommandText>SELECT ProjectID, ProjectName, ProjectDescription, DateCreated FROM Projects</CommandText>
                    
<Parameters>
                    
</Parameters>
                  
</DbCommand>
                
</SelectCommand>
                
<UpdateCommand>
                  
<DbCommand CommandType="Text" ModifiedByUser="False">
                    
<CommandText>UPDATE [Projects] SET [ProjectName] = @ProjectName, [ProjectDescription] = @ProjectDescription, [DateCreated] = @DateCreated WHERE (([ProjectID] = @Original_ProjectID) AND ([ProjectName] = @Original_ProjectName) AND ([ProjectDescription] = @Original_ProjectDescription) AND ([DateCreated] = @Original_DateCreated));
SELECT ProjectID, ProjectName, ProjectDescription, DateCreated FROM Projects WHERE (ProjectID = @ProjectID)
</CommandText>
                    
<Parameters>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@ProjectName" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="ProjectName" SourceColumnNullMapping="False" SourceVersion="Current">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@ProjectDescription" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="ProjectDescription" SourceColumnNullMapping="False" SourceVersion="Current">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="DateTime" Direction="Input" ParameterName="@DateCreated" Precision="0" ProviderType="DateTime" Scale="0" Size="0" SourceColumn="DateCreated" SourceColumnNullMapping="False" SourceVersion="Current">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="Int32" Direction="Input" ParameterName="@Original_ProjectID" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="ProjectID" SourceColumnNullMapping="False" SourceVersion="Original">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@Original_ProjectName" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="ProjectName" SourceColumnNullMapping="False" SourceVersion="Original">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@Original_ProjectDescription" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="ProjectDescription" SourceColumnNullMapping="False" SourceVersion="Original">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="" DataSourceName="" DbType="DateTime" Direction="Input" ParameterName="@Original_DateCreated" Precision="0" ProviderType="DateTime" Scale="0" Size="0" SourceColumn="DateCreated" SourceColumnNullMapping="False" SourceVersion="Original">
                      
</Parameter>
                      
<Parameter AllowDbNull="False" AutogeneratedName="ProjectID" ColumnName="ProjectID" DataSourceName="TaskVision.dbo.Projects" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@ProjectID" Precision="0" ProviderType="Int" Scale="0" Size="4" SourceColumn="ProjectID" SourceColumnNullMapping="False" SourceVersion="Current">
                      
</Parameter>
                    
</Parameters>
                  
</DbCommand>
                
</UpdateCommand>
              
</DbSource>
            
</MainSource>
            
<Mappings>
              
<Mapping SourceColumn="ProjectID" DataSetColumn="ProjectID" />
              
<Mapping SourceColumn="ProjectName" DataSetColumn="ProjectName" />
              
<Mapping SourceColumn="ProjectDescription" DataSetColumn="ProjectDescription" />
              
<Mapping SourceColumn="DateCreated" DataSetColumn="DateCreated" />
            
</Mappings>
            
<Sources>
            
</Sources>
          
</TableAdapter>
        
</Tables>
        
<Sources>
        
</Sources>
      
</DataSource>
    
</xs:appinfo>
  
</xs:annotation>
  
<xs:element name="DataSetProjects" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:Generator_UserDSName="DataSetProjects" msprop:Generator_DataSetName="DataSetProjects">
    
<xs:complexType>
      
<xs:choice minOccurs="0" maxOccurs="unbounded">
        
<xs:element name="Projects" msprop:Generator_UserTableName="Projects" msprop:Generator_RowDeletedName="ProjectsRowDeleted" msprop:Generator_TableClassName="ProjectsDataTable" msprop:Generator_RowChangedName="ProjectsRowChanged" msprop:Generator_RowClassName="ProjectsRow" msprop:Generator_RowChangingName="ProjectsRowChanging" msprop:Generator_RowEvArgName="ProjectsRowChangeEvent" msprop:Generator_RowEvHandlerName="ProjectsRowChangeEventHandler" msprop:Generator_TablePropName="Projects" msprop:Generator_TableVarName="tableProjects" msprop:Generator_RowDeletingName="ProjectsRowDeleting">
          
<xs:complexType>
            
<xs:sequence>
              
<xs:element name="ProjectID" msdata:ReadOnly="true" msdata:AutoIncrement="true" msprop:Generator_UserColumnName="ProjectID" msprop:Generator_ColumnPropNameInRow="ProjectID" msprop:Generator_ColumnVarNameInTable="columnProjectID" msprop:Generator_ColumnPropNameInTable="ProjectIDColumn" type="xs:int" />
              
<xs:element name="ProjectName" msprop:Generator_UserColumnName="ProjectName" msprop:Generator_ColumnPropNameInRow="ProjectName" msprop:Generator_ColumnVarNameInTable="columnProjectName" msprop:Generator_ColumnPropNameInTable="ProjectNameColumn">
                
<xs:simpleType>
                  
<xs:restriction base="xs:string">
                    
<xs:maxLength value="20" />
                  
</xs:restriction>
                
</xs:simpleType>
              
</xs:element>
              
<xs:element name="ProjectDescription" msprop:Generator_UserColumnName="ProjectDescription" msprop:Generator_ColumnPropNameInRow="ProjectDescription" msprop:Generator_ColumnVarNameInTable="columnProjectDescription" msprop:Generator_ColumnPropNameInTable="ProjectDescriptionColumn">
                
<xs:simpleType>
                  
<xs:restriction base="xs:string">
                    
<xs:maxLength value="100" />
                  
</xs:restriction>
                
</xs:simpleType>
              
</xs:element>
              
<xs:element name="DateCreated" msprop:Generator_UserColumnName="DateCreated" msprop:Generator_ColumnPropNameInRow="DateCreated" msprop:Generator_ColumnVarNameInTable="columnDateCreated" msprop:Generator_ColumnPropNameInTable="DateCreatedColumn" type="xs:dateTime" />
            
</xs:sequence>
          
</xs:complexType>
        
</xs:element>
      
</xs:choice>
    
</xs:complexType>
    
<xs:unique name="Constraint1" msdata:PrimaryKey="true">
      
<xs:selector xpath=".//mstns:Projects" />
      
<xs:field xpath="mstns:ProjectID" />
    
</xs:unique>
  
</xs:element>
</xs:schema>

vs2005帮你生成了对于你选定的表提供最通过的sql语句:select,update,insert,delete。这些功能都有一个TableAdapter表适配器ProjectsTableAdapter提供。
ProjectsTableAdapter还有一个方法GetData()可以取得该表的数据。返回类型为DataSetProjects.ProjectsDataTable

好了,今天就到这里了。