­

Azure Storage 系列(四)在.Net 上使用Table Storage

一,引言

  今天我们就不多说废话了,直接进入正题,Azure Table Storage。开始内容之前,我们先介绍一下Azure Table Storage.

  1,什么是Azure Table Storage

  答:Azure Table Storage 是存储结构化的 NoSql 数据的服务,通过无架构设计提供键/属性存储。 因为表存储无架构,因此可以很容易地随着应用程序需求的发展使数据适应存储。 对于许多类型的应用程序来说,访问表存储数据速度快且经济高效,在数据量相似的情况下,其成本通常比传统 SQL 要低(官方解释)。简单来说,Azure  Table Srorage 可以直接将实体,实体对象存入表结构中,和一般的关系型数据库的 Table 很像,包含了列名和行数据,但是它不能提供像SQL中 inner join 方法,也是不能管理 Foreign Key。

——————–我是分割线——————–

Azure Blob Storage 存储系列:

1,Azure Storage 系列(一)入门简介

2,Azure Storage 系列(二) .NET Core Web 项目中操作 Blob 存储

3,Azure Storage 系列(三)Blob 参数设置说明

4,Azure Storage 系列(四)在.Net 上使用Table Storage 

二,正文

1,添加对 Table Storage 的 “增,删,改,查” 方法

1.1,安装 Azure.TableStorage 相关的 Nuget 包,

NuGet:WindowsAzure.Storage(此包已被启用,推荐使用 “Microsoft.Azure.Cosmos.Table”,今天作为演示,就暂时使用当前已经遗弃的包

Install-Package WindowsAzure.Storage -Version 9.3.3

从9.4.0版本开始,此库已分为多个部分并被替换。大家可以通过当前链接进行查看当前库的状态://www.nuget.org/packages/WindowsAzure.Storage

1.2,创建 ITableService 接口,和 TableService 实现类,以及新增相应的对 Table 操作的方法

 添加Table数据操作

public async Task AddEntity(UserInfo user)
{
    var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
    var cloudTable = cloudTableClient.GetTableReference("USERINFO");
    await cloudTable.CreateIfNotExistsAsync();

    var tableOperation = TableOperation.Insert(user);
    await cloudTable.ExecuteAsync(tableOperation);
}

批量添加 Table 表数据

public async Task BatchAddEntities(List<UserInfo> users)
{
    var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
    var cloudTable = cloudTableClient.GetTableReference("USERINFO");
    await cloudTable.CreateIfNotExistsAsync();

    var tableBatchOperation = new TableBatchOperation();
    foreach (UserInfo item in users)
    {
         tableBatchOperation.Insert(item);
    }

    await cloudTable.ExecuteBatchAsync(tableBatchOperation);
 }

修改 Table 表数据

public async Task UpdateEntity(UserInfo user)
{
   var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
   var cloudTable = cloudTableClient.GetTableReference("USERINFO");

   var queryOperation = TableOperation.Retrieve<UserInfo>(user.PartitionKey, user.RowKey);

   var tableResult = await cloudTable.ExecuteAsync(queryOperation);
   if (tableResult.Result is UserInfo userInfo)
   {
        user.ETag = userInfo.ETag;
        var deleteOperation = TableOperation.Replace(user);
        await cloudTable.ExecuteAsync(deleteOperation);
   }
}

查询Table 表数据

public async IAsyncEnumerable<UserInfo> QueryUsers(string filter)
{
    var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
    var cloudTable = cloudTableClient.GetTableReference("USERINFO");

    TableQuery<UserInfo> query = new TableQuery<UserInfo>().Where(filter);

    var users = await cloudTable.ExecuteQuerySegmentedAsync<UserInfo>(query, null);
    foreach (var item in users)
    {
        yield return item;
    }
}

删除 Table 表数据

public async Task DeleteEntity(UserInfo user)
{
    var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
    var cloudTable = cloudTableClient.GetTableReference("USERINFO");

    var queryOperation = TableOperation.Retrieve<UserInfo>(user.PartitionKey, user.RowKey);

    var tableResult = await cloudTable.ExecuteAsync(queryOperation);
    if (tableResult.Result is UserInfo userInfo)
    {
        var deleteOperation = TableOperation.Delete(userInfo);
        await cloudTable.ExecuteAsync(deleteOperation);
     }
 }

删除 Table 表

public async Task DeleteTable(string tableName)
{
    var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
    var cloudTable = cloudTableClient.GetTableReference(tableName);
    await cloudTable.DeleteIfExistsAsync();
 }

1.3,添加对 TableService ,CloudStorageAccount 的注入

services.AddSingleton(x => new CloudStorageAccount(new StorageCredentials("cnbateblogaccount", "FU01h022mn1JjONp+ta0DAXOO7ThK3diYhsdsdm0Hpg891n9nycsTLGZF83nJpGvTIZvsdsdVCVFhGOfV0wndOOQ=="), true));
services.AddSingleton<ITableService, TableService>();

完整代码

  1 public class TableService : ITableService
  2     {
  3         private readonly CloudStorageAccount _cloudStorageClient;
  4         public TableService(CloudStorageAccount cloudStorageClient)
  5         {
  6             _cloudStorageClient = cloudStorageClient;
  7         }
  8 
  9         #region 01,添加表数据+async Task AddEntity(UserInfo user)
 10         /// <summary>
 11         /// 添加表数据
 12         /// </summary>
 13         /// <param name="user">用户数据</param>
 14         /// <returns></returns>
 15         public async Task AddEntity(UserInfo user)
 16         {
 17             var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
 18             var cloudTable = cloudTableClient.GetTableReference("USERINFO");
 19             await cloudTable.CreateIfNotExistsAsync();
 20 
 21             var tableOperation = TableOperation.Insert(user);
 22             await cloudTable.ExecuteAsync(tableOperation);
 23         }
 24         #endregion
 25 
 26         #region 02,批量添加用户表数据+async Task BatchAddEntities(List<UserInfo> users)
 27         /// <summary>
 28         /// 批量添加用户表数据
 29         /// </summary>
 30         /// <param name="users">用户数据</param>
 31         /// <returns></returns>
 32         public async Task BatchAddEntities(List<UserInfo> users)
 33         {
 34             var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
 35             var cloudTable = cloudTableClient.GetTableReference("USERINFO");
 36             await cloudTable.CreateIfNotExistsAsync();
 37 
 38             var tableBatchOperation = new TableBatchOperation();
 39             foreach (UserInfo item in users)
 40             {
 41                 tableBatchOperation.Insert(item);
 42             }
 43 
 44             await cloudTable.ExecuteBatchAsync(tableBatchOperation);
 45         }
 46         #endregion
 47 
 48         #region 03,删除表操作根据表名+async Task DeleteTable(string tableName)
 49         /// <summary>
 50         /// 删除表操作根据表名
 51         /// </summary>
 52         /// <param name="tableName">表命</param>
 53         /// <returns></returns>
 54         public async Task DeleteTable(string tableName)
 55         {
 56             var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
 57             var cloudTable = cloudTableClient.GetTableReference(tableName);
 58             await cloudTable.DeleteIfExistsAsync();
 59         }
 60         #endregion
 61 
 62         #region 04,删除用户数据根据用户条件+async Task DeleteEntity(UserInfo user)
 63         /// <summary>
 64         /// 删除用户数据根据用户条件
 65         /// </summary>
 66         /// <param name="user">用户条件</param>
 67         /// <returns></returns>
 68         public async Task DeleteEntity(UserInfo user)
 69         {
 70             var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
 71             var cloudTable = cloudTableClient.GetTableReference("USERINFO");
 72 
 73             var queryOperation = TableOperation.Retrieve<UserInfo>(user.PartitionKey, user.RowKey);
 74 
 75             var tableResult = await cloudTable.ExecuteAsync(queryOperation);
 76             if (tableResult.Result is UserInfo userInfo)
 77             {
 78                 var deleteOperation = TableOperation.Delete(userInfo);
 79                 await cloudTable.ExecuteAsync(deleteOperation);
 80             }
 81         }
 82         #endregion
 83 
 84         #region 05,查询用户根据条件+async IAsyncEnumerable<UserInfo> QueryUsers(string filter)
 85         /// <summary>
 86         /// 查询用户根据条件
 87         /// </summary>
 88         /// <param name="filter">条件</param>
 89         /// <returns></returns>
 90         public async IAsyncEnumerable<UserInfo> QueryUsers(string filter)
 91         {
 92             var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
 93             var cloudTable = cloudTableClient.GetTableReference("USERINFO");
 94 
 95             TableQuery<UserInfo> query = new TableQuery<UserInfo>().Where(filter);
 96 
 97             var users = await cloudTable.ExecuteQuerySegmentedAsync<UserInfo>(query, null);
 98             foreach (var item in users)
 99             {
100                 yield return item;
101             }
102         }
103         #endregion
104 
105         #region 06,更新用户表数据根据新的用户数据+async Task UpdateEntity(UserInfo user)
106         /// <summary>
107         /// 更新用户表数据根据新的用户数据
108         /// </summary>
109         /// <param name="user">新用户数据</param>
110         /// <returns></returns>
111         public async Task UpdateEntity(UserInfo user)
112         {
113             var cloudTableClient = _cloudStorageClient.CreateCloudTableClient();
114             var cloudTable = cloudTableClient.GetTableReference("USERINFO");
115 
116             var queryOperation = TableOperation.Retrieve<UserInfo>(user.PartitionKey, user.RowKey);
117 
118             var tableResult = await cloudTable.ExecuteAsync(queryOperation);
119             if (tableResult.Result is UserInfo userInfo)
120             {
121                 user.ETag = userInfo.ETag;
122                 var deleteOperation = TableOperation.Replace(user);
123                 await cloudTable.ExecuteAsync(deleteOperation);
124             }
125         } 
126         #endregion
127     }

TableService.cs

 1 public interface ITableService
 2     {
 3         Task AddEntity(UserInfo user);
 4 
 5         Task BatchAddEntities(List<UserInfo> users);
 6 
 7         IAsyncEnumerable<UserInfo> QueryUsers(string filter);
 8 
 9         Task UpdateEntity(UserInfo user);
10 
11         Task DeleteEntity(UserInfo user);
12 
13         Task DeleteTable(string tableName);
14 
15     }

ITableService.cs

 1 [Route("Table")]
 2     public class TableExplorerController : Controller
 3     {
 4         private readonly ITableService _tableService;
 5 
 6         public TableExplorerController(ITableService tableService)
 7         {
 8             this._tableService = tableService;
 9         }
10 
11         [HttpPost("AddUser")]
12         public async Task<ActionResult> AddEntity([FromBody]UserInfo user)
13         {
14             await _tableService.AddEntity(new UserInfo("zhangsan", "610124199012223650") { Email = "135012689@qq.com", TelNum = "13000000000" });
15             return Ok();
16         }
17 
18         [HttpPost("AddBatchUser")]
19         public async Task<ActionResult> AddEntities([FromBody]List<UserInfo> users)
20         {
21             List<UserInfo> userList = new List<UserInfo>();
22             userList.Add(new UserInfo("lisi", "610124199012223651") { Email = "1350126740@qq.com", TelNum = "13000000001" });
23             userList.Add(new UserInfo("lisi", "610124199012223652") { Email = "1350126741@qq.com", TelNum = "13000000002" });
24             userList.Add(new UserInfo("lisi", "610124199012223653") { Email = "1350126742@qq.com", TelNum = "13000000003" });
25             await _tableService.BatchAddEntities(userList);
26             return Ok();
27         }
28 
29         [HttpGet("Users")]
30         public ActionResult QueryUsers()
31         {
32             var filter = TableQuery.CombineFilters(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "zhangsan"), TableOperators.And, TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, "610124199012223650"));
33 
34             return Ok(_tableService.QueryUsers(filter));
35         }
36 
37         [HttpPut("UpdateUser")]
38         public async Task<ActionResult> UpdateUser([FromBody]UserInfo user)
39         {
40             await _tableService.UpdateEntity(new UserInfo("zhangsan", "610124199012223650") { Email = "135012689@qq.com", TelNum = "15000000000" });
41             return Ok();
42         }
43 
44         [HttpDelete("DeleteEntity")]
45         public async Task<ActionResult> DeleteEntity([FromBody]UserInfo user)
46         {
47             await _tableService.DeleteEntity(new UserInfo("lisi", "610124199012223651"));
48             return Ok();
49         }
50 
51         [HttpDelete("{tableName}")]
52         public async Task<ActionResult> DeleteTable(string tableName)
53         {
54             await _tableService.DeleteTable(tableName);
55             return Ok();
56         }
57     }

TableExplorerController.cs

 1 public class UserInfo:TableEntity
 2     {
 3         public UserInfo()
 4         {
 5 
 6         }
 7 
 8         public UserInfo(string userName, string IdCardNum)
 9         {
10             this.PartitionKey = userName;
11             this.RowKey = IdCardNum;
12 
13         }
14 
15         public string Email { get; set; }
16 
17         public string TelNum { get; set; }
18     }

UserInfo.cs

2,运行项目,通过接口方式调用是否可以对 Table 表数据进行操作

2.1 添加用户数据

我们在 postman 中调用添加用户表数据接口(控制器中默认构造了用户信息,所以我这边没有在Body中添加参数)

我们可以看到,在Azure Portal 上已经创建出一个叫 “USERINFO” 的表信息(注意,大家不要疑惑,可以看看上面添加用户的Service方法,我这里有两行代码)

var cloudTable = cloudTableClient.GetTableReference("USERINFO");
await cloudTable.CreateIfNotExistsAsync();

获取 “USERINFO” 表的引用实例,如果当前实例不存储就创建 “USERINFO” 表

接下来,我们看看 “USERINFO” 表中刚刚添加进去的数据,这时候我们就要借助 VS 的 “Cloud Expoere“ 的工具了

VS 点击 ”视图=》Cloud Expoere“

点击当前 ”账号管理“ 找到与之对应的自己的Azure 订阅相关联的账号

点击 ”cnbateblogaccount“ 的 Azure Storage 账号,找到刚刚创建好的 ”USERINFO“ Azure Table,右键点击”打开“

我们可以看到添加到 ”USERINFO“ 表中的数据 (注意,Timestamp字段的时间问题,这里是因为Azure Table Storage 采用的是标准时间,换算到中国时间 就得在原有时间基础上+8)

 2.2 批量添加用户数据

注意:批量添加 Table 数据的话,这些批量数据的 “PartitionKey” 必须是相同的

输入批量添加用户数据的链接,点击 “Send”

 

 我们继续回到 VS 的Cloud Explorer 查看 “USERINFO” Table 的表信息

额外话题,刚才提到批量添加 Table 表数据,有提到这些数据的 “PartitionKey” 必须一致。Azure Table Storage 对批处理操作做了一些限制

  1,单个批处理中的所有实体必须具有相同的分区键

  2,单个批处理操作只能包含100个实体。

3,查询用户数据

注意,我这里使用两个查询条件联合进行查询,分别是 “PartitionKey” 和 “RowKey” 作为查询的 Key,通过 “Partition” 等于 “zhangsan” 和 “RowKey” 等于 “610124199012113650” 

输入查询用户表数据接口,点击 “Send” 进行调用接口

同时,我们可以看到将查询条件对应的数据查询出来了

 4,更新表数据

注意,目前的更新操作时根据 “PartitionKey” 和 “RowKey” 进行检索数据,将新的用户数据进行替换操作,记得将旧的表数据中的 “ETag 也要进行赋值到新的对象中,再执行替换操作

注意,我们此时更新操作主要更新的是 “TelNum” 字段

 输入查询用户表数据接口,点击 “Send” 进行调用接口,返回状态码 200

同时我们再刷新 Table 中的数据,成功的 PartitionKey 等于 “zhangsan”,RowKey 等于 “610124199012223650” 的数据的 TelNum 从 13000000000 改为 “15000000000”

5,删除 Table 表数据

我们尝试删除 “PartitionKey” 等于 “lisi”,“RowKey” 等于 “610124199012223651”的数据

 也是根据条件先查询到当前数据,再判断是否存储,如果存在 就执行删除操作

在 postman 输入删除实体操作的接口链接,然后点击 “Sand”

 接下来,我们继续查看当前 Table 中的数据,以及没有  “PartitionKey” 等于 “lisi”,“RowKey” 等于 “610124199012223651”的数据了。

6,删除 Table 表

接下来,我们就要将整个 “SUERINFO” 表删除的操作

 继续在 postman 上调用删除 Table 操作的接口地址

当前 Table Storage 已经找不到 “USERINFO” 的 Table 信息了

 我们再上Azue Portal 上找一找,看看是否把 “USERINFO” 表删除了

对应的 cnbatebogaccount 存储账户下的 Tables 中已经没有了任何表了

OK,今天的分享到此结束,撒花🎉🎉🎉🎉🎉🎉

三,结尾

  今天,我们通过代码(已遗弃的类库)演示了一下如何操作 Tables 数据,已经创建/删除 Table,下一篇继续讲解 Table 是如果进行操作的,但是会换一套微软推荐的 “Microsoft.Azure.Cosmos.Table”,我们也要跟上微软的脚步,与时俱进。

github://github.com/yunqian44/Azure.Storage.git

作者:Allen 

版权:转载请在文章明显位置注明作者及出处。如发现错误,欢迎批评指正。

Tags: