使用Table Storage

本文是 Windows Azure 入门教学 的第六篇文章。

本文将会介绍如何使用 Table Storage。 Table Storage提供给我们一个云端的表格结构。我们可以把他想象为 XML文件或者是一个轻量级的数据库(当然,不是通过 SQL 语句进行数据的操作)。

使用 Table Storage的方法依然是调用REST API。有关 Table Storage REST API的详细信息,请参见Table服务 API:

为了方便 .NET开发人员,我们在 SDK中提供了 Microsoft.WindowsAzure.StorageClient类来帮助发送 REST请求。

在开始本教学之前,请确保你从Windows Azure 平台下载 下载并安装了最新的 Windows Azure开发工具。 本教学使用 Visual Studio 2010作为开发工具。

步骤一:创建解决方案和项目

由于我们要在本地模拟环境下测试 Table Storage,首先,请确保 Storage Emulator已经启动。我们可以找到管理器的进程手动启动或者让 Visual Studio 2010帮助我们启动他。

右击工具栏中 Windows Azure模拟器的图标,选择” Show Storage Emulator UI”。弹出如下图所示的窗口:

我们要关注的是 Service management中 Table所在的一行。要确保 Status为 Running。

确认完毕后启动 Visual Studio 2010,并且新建一个 Console项目。

步骤二:添加程序集引用

请在项目属性页里确认项目的 Target framework的值是 .NET Framework 4或 .NET Framework 3.5。然后添加对 C:/Program Files/Windows Azure SDK/v1.3/ref/Microsoft.WindowsAzure.StorageClient.dll的引用。该路径为 SDK默认安装路径,如果你不能在这个路径中找到 Microsoft.WindowsAzure.StorageClient.dll请从 SDK安装路径中寻找。

接下来添加对 System.Data.Services.Client程序集的引用。该程序集安装在 GAC中。你能够在 Add Reference窗口的 .NET标签下找到他。

步骤三:添加代码

首先在项目中的 Program.cs中引用命名空间:

using   Microsoft.WindowsAzure;
using   Microsoft.WindowsAzure.StorageClient;
然后在 Program.cs中添加如下代码 :
class   Program
{
     static   void   Main(string [] args)
     {
         var   storageAccount =  CloudStorageAccount .DevelopmentStorageAccount;
         var   tableStorage = storageAccount.CreateCloudTableClient();

         //   检查名为 CustomerInfo 的表格是否被创建,如果没有,创建它
         tableStorage.CreateTableIfNotExist("CustomerInfo" );

         //   创建表格服务上下文
         var   context =  new   CustomerInfoContext (storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);

         //  插入两条客户信息数据 , 客户 ID 分别设置为 0 和 1

         CustomerInfo   ci1 =  new   CustomerInfo () { CustomerAge = 25, CustomerID =  "0" , CustomerName =  "Mike"   };

         context.AddObject("CustomerInfo" , ci1);

          CustomerInfo   ci2 =  new   CustomerInfo () { CustomerAge = 32, CustomerID =  "1" , CustomerName =  "Peter"   };

         context.AddObject("CustomerInfo" , ci2);

         context.SaveChanges();

         //   查找 CustomerID 为 1 的客户数据并显示

         Console .WriteLine("Retrieve information of a customer whose ID is 1" );

         var   query = context.CreateQuery<CustomerInfo >("CustomerInfo" ).Where(c => c.CustomerID ==  "1" ).ToList();

         var   returnedcustomerinfo = query.FirstOrDefault();

         Console .WriteLine(string .Format("Customer info retrieved: ID:{0},Name:{1},Age:{2}" ,

             returnedcustomerinfo.CustomerID, returnedcustomerinfo.CustomerName, returnedcustomerinfo.CustomerAge));

         //   更新 CustomerID 为 1 的客户数据中的年龄

         returnedcustomerinfo.CustomerAge = 33;

         context.UpdateObject(returnedcustomerinfo);

         Console .WriteLine("**Customer Info updated**" );

         //  重新查询 , 测试更新效果

         Console .WriteLine("Retrieve information of a customer whose ID is 1" );

         var   query2 = context.CreateQuery<CustomerInfo >("CustomerInfo" ).Where(c => c.CustomerID ==  "1" ).ToList();

         var   returnedcustomerinfo2 = query.FirstOrDefault();

         Console .WriteLine(string .Format("Customer info retrieved: ID:{0},Name:{1},Age:{2}" ,

                 returnedcustomerinfo2.CustomerID, returnedcustomerinfo2.CustomerName, returnedcustomerinfo2.CustomerAge));

         //  删除插入的两条客户数据

         context.DeleteObject(ci1);

         context.DeleteObject(ci2);

         context.SaveChanges();

         Console .WriteLine("The records has been deleted" );

         Console .ReadLine();
     }
}

public   class   CustomerInfo   :  TableServiceEntity
{
     public   string   CustomerID
     {

         get   {  return   this .RowKey; }

         set   {  this .RowKey =  value ; }

     }

     public   string   CustomerName {  get ;  set ; }

     public   int   CustomerAge {  get ;  set ; }

     public   CustomerInfo()

     {

         this .PartitionKey =  "mypartitionkey" ;

     }

}

public   class   CustomerInfoContext   :  TableServiceContext

{

     public   CustomerInfoContext(string   baseAddress,  StorageCredentials   credentials) :

         base (baseAddress, credentials)

     {

     }
}
步骤四:观察并分析代码

步骤三中的代码中,首先我们通过 CloudStorageAccount.DevelopmentStorageAccount来说明我们使用的本地的 Development Storage自带账户而不是真正的云端存储服务账户。 (如果要用真实账户可以使用

//DefaultEndpointsProtocol=https 可以改成 DefaultEndpointsProtocol=http 表示用 HTTP 而不是 HTTPS

CloudStorageAccount .Parse("DefaultEndpointsProtocol=https;AccountName=[ 用户名 ];AccountKey=[ 密码 ]" );

来实例化对象 )然后通过该账户类来实例化一个 Table客户端类。这两步是使用 SDK中 StorageClient程序集来调用 Table Storage服务的必要步骤。

然后我们需要关注 System.Data.Services.Client程序集。该程序集是 WCF Data Services的客户端程序集,能够帮助我们很方便地创建 OData客户端程序。 (Table Storage提供的 REST API遵循 OData规范,因此我们的客户端需要遵循 OData规范向 Table Storage服务发送消息 )

我们需要创建上下文来调用服务,我们可以直接使用 TableServiceContext。但是通常我们会通过写一个继承自 TableServiceContext的类来实现,这样我们可以在该类中添加一些属性或者方法来更加方便地调用。上面的代码中我们继承了 TableServiceContext但是并没有添加额外的代码。在实际应用中我们可以加上一些代码来更加方便地调用。比如我们可以在 CustomerInfoContext 类中加入下面的属性:

public   IQueryable <CustomerInfo > CustomerInfo

{

     get

     {

         return   CreateQuery<CustomerInfo >("CustomerInfo" );

      }

}
这样我们就可以通过调用 context.CustomerInfo来更加代替 context.CreateQuery("CustomerInfo")。

继承自 TableServiceEntity类的 CustomerInfo 类定义了每条数据的模式。需要注意的是,与一般的关系型数据库不同, Table Storage并不要求一个表中的所有数据都遵循同一模式。举例来说,在一个表中,可以存储一条有三个字段的记录和一条只有两个字段的记录。这也是我们为什么说可以把 Table Storage想象为 XML文件的原因。当然在通常情况下我们都会需要在一个表中存储同一模式的数据。这时候我们就可以使用 System.Data.Services.Client程序集来为 Table Storage创建客户端程序。当我们需要在一个表中存储不同模式的数据时我们可以手动构建和发送 REST请求。

还有需要注意的地方是 PartitionKey和 RowKey。这两项共同组合成表的主键。详细信息,请参见理解 Table服务数据模型。

代码逻辑包括了对 Table Storage的插入,更新,删除和读取。请参考注释部分。

步骤五:运行程序

如果一切正常,你将会看到 Console程序输出如下信息:

Copyright © 2015-2026