[Azure] C# + Microsoft.Azure.Cosmos.Table v1+ Azure Storage Table - 建立 Table,刪除 Table,建立(修改)資料,列出資料,刪除資料,刪除資料 by PartitionKey

2021-01-05

最近有需要要用到 Azure Storage Table,有鑑於 https://www.nuget.org/packages/WindowsAzure.Storage/ 這套已經要被棄用了,所以我找了一下,竟然找不到 library ,他都是導向  https://www.nuget.org/packages/Microsoft.Azure.Cosmos.Table ,之後我就把 ConnectionString  放入操作了一下,竟然可以用,真的是太令人驚訝了,所以接下來的幾篇文章我們來探索一下。




前置作業 首先你要 安裝 nuget https://www.nuget.org/packages/Microsoft.Azure.Cosmos.Table ,這邊我撰寫案例是用 .net core 3.1;在 Azure Portal  開一個 儲存體帳戶,並且在左側的存取金鑰中拿到 Connection String.



1. 建立 table

//https://docs.microsoft.com/en-us/rest/api/storageservices/Delete-Table?redirectedfrom=MSDN
//delete may use 40s , create after deleting should be waiting for 40s.
var storageAccount = CloudStorageAccount.Parse(_ConnectionString);
var tableClient = storageAccount.CreateCloudTableClient(new TableClientConfiguration());
var table = tableClient.GetTableReference(tableName);
if (table.CreateIfNotExists())
{
Console.WriteLine("SUCCESS !!");
}
else
{
Console.WriteLine("ALREADY EXISTED.");
}

   
這邊需要注意的,如果你刪除這張表,你又馬上在建立,會出現 Exception

Unhandled exception. Microsoft.Azure.Cosmos.Table.StorageException: Conflict
     at Microsoft.Azure.Cosmos.Table.RestExecutor.TableCommand.Executor.ExecuteAsync[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext, CancellationToken callerCancellationToken)
     at Microsoft.Azure.Cosmos.Table.RestExecutor.TableCommand.Executor.<>c__DisplayClass0_0`1.<ExecuteSync>b__0()
     at Microsoft.Azure.Cosmos.Table.RestExecutor.Utils.RestUtility.RunWithoutSynchronizationContext[T](Func`1 actionToRun)
     at Microsoft.Azure.Cosmos.Table.RestExecutor.TableCommand.Executor.ExecuteSync[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext)
     at Microsoft.Azure.Cosmos.Table.RestExecutor.TableRestExecutor.ExecuteTableOperation[TResult](TableOperation operation, CloudTableClient client, CloudTable table, TableRequestOptions requestOptions, OperationContext operationContext)
     at Microsoft.Azure.Cosmos.Table.TableOperation.Execute(CloudTableClient client, CloudTable table, TableRequestOptions requestOptions, OperationContext operationContext)
     at Microsoft.Azure.Cosmos.Table.CloudTable.Create(TableRequestOptions requestOptions, OperationContext operationContext, String serializedIndexingPolicy, Nullable`1 throughput, Nullable`1 defaultTimeToLive)
     at Microsoft.Azure.Cosmos.Table.CloudTable.CreateIfNotExists(TableRequestOptions requestOptions, OperationContext operationContext, String serializedIndexingPolicy, Nullable`1 throughput, Nullable`1 defaultTimeToLive)
     at TestAzureStorageTable2020.Program.CreateTable(String tableName) in C:\Users\donma\source\repos\TestAzureStorageTable2020\TestAzureStorageTable2020\Program.cs:line 72
     at TestAzureStorageTable2020.Program.Main(String[] args) in C:\Users\donma\source\repos\TestAzureStorageTable2020\TestAzureStorageTable2020\Program.cs:line 40
Request Information
RequestID:7b683220-d002-0066-7622-e31c6e000000
RequestDate:Tue, 05 Jan 2021 05:21:49 GMT
StatusMessage:Conflict
ErrorCode:
ErrorMessage:The specified table is being deleted. Try operation later.

這邊注意,大概需要 40 秒的時間給 Azure CD ?

2.刪除 Table

var storageAccount = CloudStorageAccount.Parse(_ConnectionString);
var tableClient = storageAccount.CreateCloudTableClient(new TableClientConfiguration());
var res = tableClient.GetTableReference(tableName).DeleteIfExists();
if (res)
{
Console.WriteLine("SUCCESS !!");
}
else
{
Console.WriteLine("NO EXISTED TABLE.");
}

3.建立資料,這邊有點點跟SQL 想法不同,首先你建立一個物件,必須要繼承  Microsoft.Azure.Cosmos.Table.TableEntity, 這時候因為繼承關係,你就會 擁有這些 Property

ETag   
獲取或設置實體的ETag。將此值設置為“ *”,以作為更新操作的一部分強制覆蓋實體。

PartitionKey   
分區Key

RowKey 
在我的理解,它是在 PartitionKey 下的 Key

Timestamp   
時間戳,通常這是 Azure Storage Table 寫入時會自動寫入的

繼承 Microsoft.Azure.Cosmos.Table.TableEntity 後 就可以寫入

var tableClient = CloudStorageAccount.Parse(_ConnectionString).CreateCloudTableClient(new TableClientConfiguration());
var table = tableClient.GetTableReference("table1");
for (var i = 1; i <= 100; i++)
{
var sampleObject = new User("CLASSA", "DATAKEY" + i)
{
Name = "DONMA" + i,
Age = i,
Create = new DateTime(2010, 1, 1).AddDays(i)
};
var upsertOperation = TableOperation.InsertOrReplace(sampleObject);
var result = table.Execute(upsertOperation);
Console.WriteLine("PartitionKey:" + (result.Result as User).PartitionKey + "," +
"RowKey:" + (result.Result as User).RowKey + "," +
"ETag:" + result.Etag);
}
public class User : Microsoft.Azure.Cosmos.Table.TableEntity
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime Create { get; set; }
public List<User> Friends { get; set; }
public User() {
Friends = new List<User>();
}
public User(string classId, string userId)
{
PartitionKey = classId;
RowKey = userId;
Friends = new List<User>();
}
}


這裡我的 PartitionKey    都是設定成 CLASSA , RowKey 則為 DATAKEY1~DATAKEY100

4. 列出所有資料


var tableClient = CloudStorageAccount.Parse(_ConnectionString).CreateCloudTableClient(new TableClientConfiguration());
var table = tableClient.GetTableReference("table1");
var queryResult = table.ExecuteQuery(new TableQuery<User>(), null);
var count = 0;
foreach (var data in queryResult)
{
Console.WriteLine(JsonConvert.SerializeObject(data));
count++;
}
Console.WriteLine("--");
Console.WriteLine("DATA COUNT:" + count);


5.刪除單一檔案,案例為 PartitionKey  : CLASSA  , RowKey  : DATAKEY11

var tableClient = CloudStorageAccount.Parse(_ConnectionString).CreateCloudTableClient(new TableClientConfiguration());
var table = tableClient.GetTableReference("table1");
try
{
var deleteReult = table.Execute(TableOperation.Delete(new TableEntity { RowKey = "DATAKEY11", PartitionKey = "CLASSA", ETag = "*" }));
Console.WriteLine("SUCCESS");
}
catch (Exception ex)
{
Console.WriteLine("Error:" + ex.Message);
}


6. 刪除資料 by PartitionKey ,撈出所有 PartitionKey 為 CLASSA ,的資料後刪除所有,這邊是先撈取再刪除,撈取時候使用 GenerateFilterCondition 只撈取 PartitionKey  , RowKey  減少回傳量,之後再使用 TableBatchOperation , ExecuteBatch 進行批次刪除


var tableClient = CloudStorageAccount.Parse(_ConnectionString).CreateCloudTableClient(new TableClientConfiguration());
var table = tableClient.GetTableReference("table1");
var queryAllRowKeysByPK = new TableQuery().Where(TableQuery.GenerateFilterCondition("PartitionKey",
QueryComparisons.Equal, "CLASSA")).Select(new[] { "RowKey" });
var entities = table.ExecuteQuery(queryAllRowKeysByPK);
var batch = new TableBatchOperation();
foreach (var wannaDeleteData in entities)
{
batch.Add(TableOperation.Delete(wannaDeleteData));
}
try
{
table.ExecuteBatch(batch);
Console.WriteLine("SUCCESS");
}
catch (Exception ex)
{
Console.WriteLine("Error:" + ex.Message);
}



reference:
https://docs.microsoft.com/en-us/rest/api/storageservices/Delete-Table?redirectedfrom=MSDN
https://raflrx.wordpress.com/2017/09/29/batch-delete-entities-in-azure-table-storage/
https://stackoverflow.com/questions/26326413/delete-all-azure-table-records
https://stackoverflow.com/questions/168901/count-the-items-from-a-ienumerablet-without-iterating
https://stackoverflow.com/questions/62945338/azure-c-sharp-function-how-to-read-from-table-storage
https://docs.microsoft.com/en-us/rest/api/storageservices/Delete-Table?redirectedfrom=MSDN


當麻許的超技八 2014 | Donma Hsu Design.