Windows Azure入门教学系列 (六):使用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>("CustomerInfo")。

 

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

 

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

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

步骤五:运行程序

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