123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- 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 批次操作
- /// <summary>
- /// 批次新增資料至Table儲存區。
- /// </summary>
- /// <param name="entities">欲快取的集合</param>
- /// <returns></returns>
- public static async Task<TableBatchResult> BatchInsertAsync<T>(this CloudTable table, IEnumerable<T> 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
- /// <summary>
- /// (同步)取得 table 中指定 PartitionKey 的所有集合。
- /// </summary>
- /// <returns></returns>
- public static IEnumerable<T> Get<T>(this CloudTable table, string partitionKey) where T : ITableEntity, new()
- {
- TableQuery<T> query = new TableQuery<T>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey));
- return table.ExecuteQuery(query);
- }
- /// <summary>
- /// (同步)取得指定 PartitionKey與 RowKey 的數據,效能:點查詢,最佳。
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- /// <param name="partitionKey">PartitionKey</param>
- /// <param name="rowKey">RowKey</param>
- /// <returns></returns>
- public static T Get<T>(this CloudTable table, string partitionKey, string rowKey) where T : ITableEntity, new()
- {
- TableOperation retrieveOperation = TableOperation.Retrieve<T>(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;
- }
- }
- /// <summary>
- /// 取得指定 PartitionKey 的所有集合(分頁),效能:範圍查詢,次佳。
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- /// <param name="partitionKey">PartitionKey</param>
- /// <param name="takeCount">指定每次返回數量</param>
- /// <param name="specifyPropertys">指定只須返回的屬性,效能:伺服器端預測,降低延遲和成本</param>
- /// <param name="onProgress">要返回集合的委派</param>
- /// <param name="ct">CancellationToken</param>
- /// <returns></returns>
- public static async Task GetAsync<T>(this CloudTable table, string partitionKey, int? takeCount = null, List<string> specifyPropertys = null, Action<IList<T>> onProgress = null, CancellationToken ct = default(CancellationToken)) where T : ITableEntity, new()
- {
- TableQuery<T> tableQuery = null;
- TableContinuationToken token = null;
- var filter = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey);
- if (specifyPropertys != null)
- tableQuery = new TableQuery<T>().Where(filter).Select(specifyPropertys);
- else
- tableQuery = new TableQuery<T>().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);
- }
- /// <summary>
- /// 取得指定 PartitionKey 的所有集合,效能:範圍查詢,次佳。
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- /// <param name="partitionKey">PartitionKey</param>
- /// <param name="takeCount">指定每次返回數量</param>
- /// <param name="specifyPropertys">指定只須返回的屬性,效能:伺服器端預測,降低延遲和成本</param>
- /// <param name="onProgress">要返回集合的委派</param>
- /// <param name="ct">CancellationToken</param>
- /// <returns></returns>
- public static async Task<IEnumerable<T>> GetAsync<T>(this CloudTable table, string partitionKey, int? takeCount = null, List<string> specifyPropertys = null, CancellationToken ct = default(CancellationToken)) where T : ITableEntity, new()
- {
- TableQuery<T> tableQuery = null;
- TableContinuationToken token = null;
- var filter = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey);
- if (specifyPropertys != null)
- tableQuery = new TableQuery<T>().Where(filter).Select(specifyPropertys);
- else
- tableQuery = new TableQuery<T>().Where(filter);
- if (takeCount != null) tableQuery.TakeCount = takeCount;
- var items = new List<T>();
- do
- {
- var queryResponse = await table.ExecuteQuerySegmentedAsync(tableQuery, token);
- token = queryResponse.ContinuationToken;
- items.AddRange(queryResponse.Results);
- } while (token != null && !ct.IsCancellationRequested);
- return items;
- }
- /// <summary>
- /// 傳回指定partitionKey的Count數量
- /// </summary>
- /// <param name="partitionKey"></param>
- /// <returns></returns>
- public static int GetCount(this CloudTable table, string partitionKey)
- {
- TableQuery query = new TableQuery().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey)).Select(new List<string> { "PartitionKey" });
- var queryResponse = table.ExecuteQuery(query).ToList();
- return queryResponse.Count();
- }
- #endregion
- #region CloudTable Get All
- /// <summary>
- /// (同步)取得 table 的所有集合,效能:資料表掃描,不佳。
- /// </summary>
- /// <returns></returns>
- public static IEnumerable<T> GetAll<T>(this CloudTable table) where T : ITableEntity, new()
- {
- return table.ExecuteQuery(new TableQuery<T>());
- }
- /// <summary>
- /// 取得 table 的所有集合(分頁),效能:資料表掃描,不佳。
- /// </summary>
- /// <param name="takeCount">指定每次返回數量</param>
- /// <param name="specifyPropertys">指定只須返回的屬性,效能:伺服器端預測,降低延遲和成本</param>
- /// <param name="onProgress">要返回集合的委派</param>
- /// <returns></returns>
- public static async Task GetAllAsync<T>(this CloudTable table, int? takeCount = null, List<string> specifyPropertys = null, Action<IList<T>> onProgress = null, CancellationToken ct = default(CancellationToken)) where T : ITableEntity, new()
- {
- TableContinuationToken token = null;
- TableQuery<T> tableQuery = new TableQuery<T>();
- if (specifyPropertys != null)
- tableQuery = new TableQuery<T>().Select(specifyPropertys);
- else
- tableQuery = new TableQuery<T>();
- if (takeCount != null) tableQuery.TakeCount = takeCount;
- var items = new List<T>();
- do
- {
- var queryResponse = await table.ExecuteQuerySegmentedAsync(tableQuery, token);
- token = queryResponse.ContinuationToken;
- items.AddRange(queryResponse.Results);
- onProgress?.Invoke(queryResponse.Results);
- } while (token != null && !ct.IsCancellationRequested);
- }
- /// <summary>
- /// 取得 table 的所有集合,效能:資料表掃描,不佳。
- /// </summary>
- /// <param name="takeCount">指定每次返回數量</param>
- /// <param name="specifyPropertys">指定只須返回的屬性,效能:伺服器端預測,降低延遲和成本</param>
- /// <returns></returns>
- public static async Task<IEnumerable<T>> GetAllAsync<T>(this CloudTable table, int? takeCount = null, List<string> specifyPropertys = null, CancellationToken ct = default(CancellationToken)) where T : ITableEntity, new()
- {
- TableContinuationToken token = null;
- TableQuery<T> tableQuery = new TableQuery<T>();
- if (takeCount != null) tableQuery.TakeCount = takeCount;
- if (specifyPropertys != null)
- tableQuery = new TableQuery<T>().Select(specifyPropertys);
- else
- tableQuery = new TableQuery<T>();
- var items = new List<T>();
- 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<T> Save<T>(this AzureStorageFactory azureStorage, TableEntity entity) where T : TableEntity, new()
- {
- CloudTable TableName = await azureStorage.InitializeTable<T>();
- TableOperation operation = TableOperation.Insert(entity);
- TableResult result = await TableName.ExecuteAsync(operation);
- return (T)result.Result;
- }
- public static async Task<T> SaveOrUpdate<T>(this AzureStorageFactory azureStorage, TableEntity entity) where T : TableEntity, new()
- {
- CloudTable TableName = await azureStorage.InitializeTable<T>();
- TableOperation operation = TableOperation.InsertOrReplace(entity);
- TableResult result = await TableName.ExecuteAsync(operation);
- return (T)result.Result;
- }
- public static async Task<T> Update<T>(this AzureStorageFactory azureStorage, TableEntity entity) where T : TableEntity, new()
- {
- CloudTable TableName = await azureStorage.InitializeTable<T>();
- TableOperation operation = TableOperation.Replace(entity);
- TableResult result = await TableName.ExecuteAsync(operation);
- return (T)result.Result;
- }
- public static async Task<T> Delete<T>(this AzureStorageFactory azureStorage, TableEntity entity) where T : TableEntity, new()
- {
- CloudTable TableName = await azureStorage.InitializeTable<T>();
- TableOperation operation = TableOperation.Delete(entity);
- TableResult result = await TableName.ExecuteAsync(operation);
- return (T)result.Result;
- }
- public static async Task<List<T>> DeleteAll<T>(this AzureStorageFactory azureStorage, List<T> entitys) where T : TableEntity, new()
- {
- if (!entitys.IsNotEmpty())
- {
- return null;
- }
- CloudTable TableName = await azureStorage.InitializeTable<T>();
- IList<Dictionary<string, List<T>>> listInfo = new List<Dictionary<string, List<T>>>();
- foreach (IGrouping<string, T> group in entitys.GroupBy(c => c.PartitionKey))
- {
- Dictionary<string, List<T>> dictInfo = new Dictionary<string, List<T>>
- {
- { group.Key, group.ToList() }
- };
- listInfo.Add(dictInfo);
- }
- foreach (Dictionary<string, List<T>> dict in listInfo)
- {
- IList<TableResult> result = null;
- foreach (string key in dict.Keys)
- {
- List<T> values = dict[key];
-
- int pageSize = 100;
- int pages = (int)Math.Ceiling((double)values.Count / pageSize);
- for (int i = 0; i < pages; i++)
- {
- List<T> 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<List<T>> SaveOrUpdateAll<T>(this AzureStorageFactory azureStorage, List<T> entitys) where T : TableEntity, new()
- {
- if (!entitys.IsNotEmpty())
- {
- return null;
- }
- CloudTable TableName = await azureStorage.InitializeTable<T>();
- IList<Dictionary<string, List<T>>> listInfo = new List<Dictionary<string, List<T>>>();
- foreach (IGrouping<string, T> group in entitys.GroupBy(c => c.PartitionKey))
- {
- Dictionary<string, List<T>> dictInfo = new Dictionary<string, List<T>>
- {
- { group.Key, group.ToList() }
- };
- listInfo.Add(dictInfo);
- }
- foreach (Dictionary<string, List<T>> dict in listInfo)
- {
- IList<TableResult> result = null;
- foreach (string key in dict.Keys)
- {
- List<T> values = dict[key];
- int pageSize = 100;
- int pages = (int)Math.Ceiling((double)values.Count / pageSize);
- for (int i = 0; i < pages; i++)
- {
- List<T> 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<List<T>> UpdateAll<T>(this AzureStorageFactory azureStorageFactory, List<T> entitys) where T : TableEntity, new()
- {
- if (!entitys.IsNotEmpty())
- {
- return null;
- }
- CloudTable TableName = await azureStorageFactory.InitializeTable<T>();
- IList<Dictionary<string, List<T>>> listInfo = new List<Dictionary<string, List<T>>>();
- foreach (IGrouping<string, T> group in entitys.GroupBy(c => c.PartitionKey))
- {
- Dictionary<string, List<T>> dictInfo = new Dictionary<string, List<T>>
- {
- { group.Key, group.ToList() }
- };
- listInfo.Add(dictInfo);
- }
- foreach (Dictionary<string, List<T>> dict in listInfo)
- {
- IList<TableResult> result = null;
- foreach (string key in dict.Keys)
- {
- List<T> values = dict[key];
-
- int pageSize = 100;
- int pages = (int)Math.Ceiling((double)values.Count / pageSize);
- for (int i = 0; i < pages; i++)
- {
- List<T> 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<List<T>> SaveAll<T>(this AzureStorageFactory azureStorage, List<T> entitys) where T : TableEntity, new()
- {
- if (!entitys.IsNotEmpty())
- {
- return null;
- }
- CloudTable TableName = await azureStorage.InitializeTable<T>();
- IList<Dictionary<string, List<T>>> listInfo = new List<Dictionary<string, List<T>>>();
- foreach (IGrouping<string, T> group in entitys.GroupBy(c => c.PartitionKey))
- {
- Dictionary<string, List<T>> dictInfo = new Dictionary<string, List<T>>
- {
- { group.Key, group.ToList() }
- };
- listInfo.Add(dictInfo);
- }
- foreach (Dictionary<string, List<T>> dict in listInfo)
- {
- IList<TableResult> result = null;
- foreach (string key in dict.Keys)
- {
- List<T> values = dict[key];
-
- int pageSize = 100;
- int pages = (int)Math.Ceiling((double)values.Count / pageSize);
- for (int i = 0; i < pages; i++)
- {
- List<T> 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<List<T>> FindListByDict<T>(this AzureStorageFactory azureStorage, Dictionary<string, object> dict) where T : TableEntity, new()
- {
- CloudTable TableName = await azureStorage.InitializeTable<T>();
- var exQuery = new TableQuery<T>();
- 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<T>(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<T>(exQuery, TableName);
- }
- else
- {
- return null;
- }
- }
- private static async Task<List<T>> QueryList<T>(TableQuery<T> exQuery, CloudTable TableName ) where T : TableEntity, new()
- {
- TableContinuationToken continuationToken = null;
- List<T> entitys = new List<T>();
- 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<T>(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;
- }
- }
- }
- }
|