using Microsoft.Azure.Cosmos.Table; using Microsoft.Azure.Cosmos.Table.Queryable; using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Linq; using TEAMModelOS.SDK.Helper.Common.CollectionHelper; using System.Reflection; namespace TEAMModelOS.SDK.DI { public static class AzureStorageTableExtensions { #region CloudTable 批次操作 /// /// 批次新增資料至Table儲存區。 /// /// 欲快取的集合 /// public static async Task BatchInsertAsync(this CloudTable table, IEnumerable entities) where T : ITableEntity, new() { TableBatchOperation batchOperation = new TableBatchOperation(); foreach (var cache in entities) { batchOperation.Insert(cache); } return await table.ExecuteBatchAsync(batchOperation); } #endregion #region CloudTable Get /// /// (同步)取得 table 中指定 PartitionKey 的所有集合。 /// /// public static IEnumerable Get(this CloudTable table, string partitionKey) where T : ITableEntity, new() { TableQuery query = new TableQuery().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey)); return table.ExecuteQuery(query); } /// /// (同步)取得指定 PartitionKey與 RowKey 的數據,效能:點查詢,最佳。 /// /// T /// PartitionKey /// RowKey /// public static T Get(this CloudTable table, string partitionKey, string rowKey) where T : ITableEntity, new() { TableOperation retrieveOperation = TableOperation.Retrieve(partitionKey, rowKey); var retrieveResult = table.Execute(retrieveOperation); if (retrieveResult.Result != null) { //DynamicTableEntityJsonSeria1lizer return (T)retrieveResult.Result; } else { return default(T); } } public static DynamicTableEntity Get(this CloudTable table, string partitionKey, string rowKey) { TableOperation retrieveOperation = TableOperation.Retrieve(partitionKey, rowKey); var retrieveResult = table.Execute(retrieveOperation); if (retrieveResult.Result != null) { return retrieveResult.Result as DynamicTableEntity; } else { return null; } } /// /// 取得指定 PartitionKey 的所有集合(分頁),效能:範圍查詢,次佳。 /// /// T /// PartitionKey /// 指定每次返回數量 /// 指定只須返回的屬性,效能:伺服器端預測,降低延遲和成本 /// 要返回集合的委派 /// CancellationToken /// public static async Task GetAsync(this CloudTable table, string partitionKey, int? takeCount = null, List specifyPropertys = null, Action> onProgress = null, CancellationToken ct = default(CancellationToken)) where T : ITableEntity, new() { TableQuery tableQuery = null; TableContinuationToken token = null; var filter = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey); if (specifyPropertys != null) tableQuery = new TableQuery().Where(filter).Select(specifyPropertys); else tableQuery = new TableQuery().Where(filter); if (takeCount != null) tableQuery.TakeCount = takeCount; do { var queryResponse = await table.ExecuteQuerySegmentedAsync(tableQuery, token); token = queryResponse.ContinuationToken; onProgress?.Invoke(queryResponse.Results); } while (token != null && !ct.IsCancellationRequested); } /// /// 取得指定 PartitionKey 的所有集合,效能:範圍查詢,次佳。 /// /// T /// PartitionKey /// 指定每次返回數量 /// 指定只須返回的屬性,效能:伺服器端預測,降低延遲和成本 /// 要返回集合的委派 /// CancellationToken /// public static async Task> GetAsync(this CloudTable table, string partitionKey, int? takeCount = null, List specifyPropertys = null, CancellationToken ct = default(CancellationToken)) where T : ITableEntity, new() { TableQuery tableQuery = null; TableContinuationToken token = null; var filter = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey); if (specifyPropertys != null) tableQuery = new TableQuery().Where(filter).Select(specifyPropertys); else tableQuery = new TableQuery().Where(filter); if (takeCount != null) tableQuery.TakeCount = takeCount; var items = new List(); do { var queryResponse = await table.ExecuteQuerySegmentedAsync(tableQuery, token); token = queryResponse.ContinuationToken; items.AddRange(queryResponse.Results); } while (token != null && !ct.IsCancellationRequested); return items; } /// /// 傳回指定partitionKey的Count數量 /// /// /// public static int GetCount(this CloudTable table, string partitionKey) { TableQuery query = new TableQuery().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey)).Select(new List { "PartitionKey" }); var queryResponse = table.ExecuteQuery(query).ToList(); return queryResponse.Count(); } #endregion #region CloudTable Get All /// /// (同步)取得 table 的所有集合,效能:資料表掃描,不佳。 /// /// public static IEnumerable GetAll(this CloudTable table) where T : ITableEntity, new() { return table.ExecuteQuery(new TableQuery()); } /// /// 取得 table 的所有集合(分頁),效能:資料表掃描,不佳。 /// /// 指定每次返回數量 /// 指定只須返回的屬性,效能:伺服器端預測,降低延遲和成本 /// 要返回集合的委派 /// public static async Task GetAllAsync(this CloudTable table, int? takeCount = null, List specifyPropertys = null, Action> onProgress = null, CancellationToken ct = default(CancellationToken)) where T : ITableEntity, new() { TableContinuationToken token = null; TableQuery tableQuery = new TableQuery(); if (specifyPropertys != null) tableQuery = new TableQuery().Select(specifyPropertys); else tableQuery = new TableQuery(); if (takeCount != null) tableQuery.TakeCount = takeCount; var items = new List(); do { var queryResponse = await table.ExecuteQuerySegmentedAsync(tableQuery, token); token = queryResponse.ContinuationToken; items.AddRange(queryResponse.Results); onProgress?.Invoke(queryResponse.Results); } while (token != null && !ct.IsCancellationRequested); } /// /// 取得 table 的所有集合,效能:資料表掃描,不佳。 /// /// 指定每次返回數量 /// 指定只須返回的屬性,效能:伺服器端預測,降低延遲和成本 /// public static async Task> GetAllAsync(this CloudTable table, int? takeCount = null, List specifyPropertys = null, CancellationToken ct = default(CancellationToken)) where T : ITableEntity, new() { TableContinuationToken token = null; TableQuery tableQuery = new TableQuery(); if (takeCount != null) tableQuery.TakeCount = takeCount; if (specifyPropertys != null) tableQuery = new TableQuery().Select(specifyPropertys); else tableQuery = new TableQuery(); var items = new List(); do { var queryResponse = await table.ExecuteQuerySegmentedAsync(tableQuery, token); token = queryResponse.ContinuationToken; items.AddRange(queryResponse.Results); } while (token != null && !ct.IsCancellationRequested); return items; } #endregion public static async Task Save(this AzureStorageFactory azureStorage, TableEntity entity) where T : TableEntity, new() { CloudTable TableName = await azureStorage.InitializeTable(); TableOperation operation = TableOperation.Insert(entity); TableResult result = await TableName.ExecuteAsync(operation); return (T)result.Result; } public static async Task SaveOrUpdate(this AzureStorageFactory azureStorage, TableEntity entity) where T : TableEntity, new() { CloudTable TableName = await azureStorage.InitializeTable(); TableOperation operation = TableOperation.InsertOrReplace(entity); TableResult result = await TableName.ExecuteAsync(operation); return (T)result.Result; } public static async Task Update(this AzureStorageFactory azureStorage, TableEntity entity) where T : TableEntity, new() { CloudTable TableName = await azureStorage.InitializeTable(); TableOperation operation = TableOperation.Replace(entity); TableResult result = await TableName.ExecuteAsync(operation); return (T)result.Result; } public static async Task Delete(this AzureStorageFactory azureStorage, TableEntity entity) where T : TableEntity, new() { CloudTable TableName = await azureStorage.InitializeTable(); TableOperation operation = TableOperation.Delete(entity); TableResult result = await TableName.ExecuteAsync(operation); return (T)result.Result; } public static async Task> DeleteAll(this AzureStorageFactory azureStorage, List entitys) where T : TableEntity, new() { if (entitys.IsEmpty()) { return null; } CloudTable TableName = await azureStorage.InitializeTable(); IList>> listInfo = new List>>(); foreach (IGrouping group in entitys.GroupBy(c => c.PartitionKey)) { Dictionary> dictInfo = new Dictionary> { { group.Key, group.ToList() } }; listInfo.Add(dictInfo); } foreach (Dictionary> dict in listInfo) { IList result = null; foreach (string key in dict.Keys) { List values = dict[key]; int pageSize = 100; int pages = (int)Math.Ceiling((double)values.Count / pageSize); for (int i = 0; i < pages; i++) { List lists = values.Skip((i) * pageSize).Take(pageSize).ToList(); TableBatchOperation batchOperation = new TableBatchOperation(); for (int j = 0; j < lists.Count; j++) { batchOperation.Delete(lists[j]); } result = await TableName.ExecuteBatchAsync(batchOperation); } } } return entitys; } public static async Task> SaveOrUpdateAll(this AzureStorageFactory azureStorage, List entitys) where T : TableEntity, new() { if (entitys.IsEmpty()) { return null; } CloudTable TableName = await azureStorage.InitializeTable(); IList>> listInfo = new List>>(); foreach (IGrouping group in entitys.GroupBy(c => c.PartitionKey)) { Dictionary> dictInfo = new Dictionary> { { group.Key, group.ToList() } }; listInfo.Add(dictInfo); } foreach (Dictionary> dict in listInfo) { IList result = null; foreach (string key in dict.Keys) { List values = dict[key]; int pageSize = 100; int pages = (int)Math.Ceiling((double)values.Count / pageSize); for (int i = 0; i < pages; i++) { List lists = values.Skip((i) * pageSize).Take(pageSize).ToList(); TableBatchOperation batchOperation = new TableBatchOperation(); for (int j = 0; j < lists.Count; j++) { batchOperation.InsertOrReplace(lists[j]); } result = await TableName.ExecuteBatchAsync(batchOperation); } } } return entitys; } public static async Task> UpdateAll(this AzureStorageFactory azureStorageFactory, List entitys) where T : TableEntity, new() { if (entitys.IsEmpty()) { return null; } CloudTable TableName = await azureStorageFactory.InitializeTable(); IList>> listInfo = new List>>(); foreach (IGrouping group in entitys.GroupBy(c => c.PartitionKey)) { Dictionary> dictInfo = new Dictionary> { { group.Key, group.ToList() } }; listInfo.Add(dictInfo); } foreach (Dictionary> dict in listInfo) { IList result = null; foreach (string key in dict.Keys) { List values = dict[key]; int pageSize = 100; int pages = (int)Math.Ceiling((double)values.Count / pageSize); for (int i = 0; i < pages; i++) { List lists = values.Skip((i) * pageSize).Take(pageSize).ToList(); TableBatchOperation batchOperation = new TableBatchOperation(); for (int j = 0; j < lists.Count; j++) { batchOperation.Replace(lists[j]); } result = await TableName.ExecuteBatchAsync(batchOperation); } } } return entitys; } public static async Task> SaveAll(this AzureStorageFactory azureStorage, List entitys) where T : TableEntity, new() { if (entitys.IsEmpty()) { return null; } CloudTable TableName = await azureStorage.InitializeTable(); IList>> listInfo = new List>>(); foreach (IGrouping group in entitys.GroupBy(c => c.PartitionKey)) { Dictionary> dictInfo = new Dictionary> { { group.Key, group.ToList() } }; listInfo.Add(dictInfo); } foreach (Dictionary> dict in listInfo) { IList result = null; foreach (string key in dict.Keys) { List values = dict[key]; int pageSize = 100; int pages = (int)Math.Ceiling((double)values.Count / pageSize); for (int i = 0; i < pages; i++) { List lists = values.Skip((i) * pageSize).Take(pageSize).ToList(); TableBatchOperation batchOperation = new TableBatchOperation(); for (int j = 0; j < lists.Count; j++) { batchOperation.Insert(lists[j]); } result = await TableName.ExecuteBatchAsync(batchOperation); } } } return entitys; } public static async Task> FindListByDict(this AzureStorageFactory azureStorage, Dictionary dict) where T : TableEntity, new() { CloudTable TableName = await azureStorage.InitializeTable(); var exQuery = new TableQuery(); StringBuilder builder = new StringBuilder(); if (null != dict && dict.Count > 0) { var keys = dict.Keys; int index = 1; foreach (string key in keys) { if (dict[key] != null && !string.IsNullOrEmpty(dict[key].ToString())) { string typeStr = SwitchType(dict[key], key); if (string.IsNullOrEmpty(typeStr)) { continue; } if (index == 1) { //builder.Append(TableQuery.GenerateFilterCondition(key, QueryComparisons.Equal, dict[key].ToString())); builder.Append(typeStr); } else { //builder.Append(" " + TableOperators.And + " " + TableQuery.GenerateFilterCondition(key, QueryComparisons.Equal, dict[key].ToString())); builder.Append(" " + TableOperators.And + " " + typeStr); } index++; } else { throw new Exception("The parameter must have value!"); } } exQuery.Where(builder.ToString()); return await QueryList(exQuery, TableName); } else { return null; } } private static async Task> QueryList(TableQuery exQuery, CloudTable TableName ) where T : TableEntity, new() { TableContinuationToken continuationToken = null; List entitys = new List(); do { var result = await TableName.ExecuteQuerySegmentedAsync(exQuery, continuationToken); if (result.Results.Count > 0) { entitys.AddRange(result.ToList()); } continuationToken = result.ContinuationToken; } while (continuationToken != null); return entitys; } private static string SwitchType(object obj, string key) { Type objType = typeof(T); PropertyInfo property = objType.GetProperty(key); //Type s = obj.GetType(); //TypeCode typeCode = Type.GetTypeCode(s); if (property == null) { //return null; throw new Exception(objType.FullName + " PropertyInfo doesn't include this parameter :" + key); } TypeCode typeCode = Type.GetTypeCode(property.PropertyType); switch (typeCode) { case TypeCode.String: return TableQuery.GenerateFilterCondition(key, QueryComparisons.Equal, obj.ToString()); case TypeCode.Int32: return TableQuery.GenerateFilterConditionForInt(key, QueryComparisons.Equal, int.Parse(obj.ToString())); case TypeCode.Double: return TableQuery.GenerateFilterConditionForDouble(key, QueryComparisons.Equal, (double)obj); case TypeCode.Byte: return TableQuery.GenerateFilterConditionForBinary(key, QueryComparisons.Equal, (byte[])obj); case TypeCode.Boolean: return TableQuery.GenerateFilterConditionForBool(key, QueryComparisons.Equal, (bool)obj); case TypeCode.DateTime: return TableQuery.GenerateFilterConditionForDate(key, QueryComparisons.Equal, (DateTimeOffset)obj); case TypeCode.Int64: return TableQuery.GenerateFilterConditionForLong(key, QueryComparisons.Equal, long.Parse(obj.ToString())); default: return null; } } } }