1. 程式人生 > >Azure Storage 系列(四)在.Net 上使用Table Storage

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 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版本開始,此庫已分為多個部分並被替換。大家可以通過當前連結進行檢視當前庫的狀態:https://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 = "[email protected]", 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 = "[email protected]", TelNum = "13000000001" });
23             userList.Add(new UserInfo("lisi", "610124199012223652") { Email = "[email protected]", TelNum = "13000000002" });
24             userList.Add(new UserInfo("lisi", "610124199012223653") { Email = "[email protected]", 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 = "[email protected]", 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,今天的分享到此結束,撒花