Browse Source

1.完成CosmosDB 微软最新官方文档的SDK验证及基本操作方法封装,支持Text.Json序列化。
2.支持参数化查询,防止SQL注入。
4.实现对动态Linq查询支持。

CrazyIter 5 years ago
parent
commit
a82ea07924

+ 617 - 0
TEAMModelOS.SDK/Module/AzureCosmosDBV3/AzureCosmosDBV3Repository.cs

@@ -0,0 +1,617 @@
+using Microsoft.Azure.Cosmos;
+using Microsoft.Azure.Cosmos.Linq;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Net;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.Context.Attributes.Azure;
+using TEAMModelOS.SDK.Context.Exception;
+using TEAMModelOS.SDK.Helper.Common.ReflectorExtensions;
+using TEAMModelOS.SDK.Module.AzureCosmosDB.Configuration;
+
+namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
+{
+    public class AzureCosmosDBV3Repository : IAzureCosmosDBV3Repository, IDisposable
+    {
+        private CosmosClient CosmosClient { get; set; }
+        /// <summary>
+        /// 线程安全的dict类型
+        /// </summary>
+        private Dictionary<string, Container> DocumentCollectionDict { get; set; } = new Dictionary<string, Container>();
+
+        private string DatabaseId { get; set; }
+        private int CollectionThroughput { get; set; }
+        private Database database = null;
+
+        private string[] ScanModel { get; set; }
+
+        public AzureCosmosDBV3Repository(AzureCosmosDBOptions options)
+        {
+            try
+            {
+                if (!string.IsNullOrEmpty(options.ConnectionString))
+                {
+                    CosmosClient = CosmosDBV3ClientSingleton.getInstance(options.ConnectionString, options.ConnectionKey).GetCosmosDBClient();
+
+                }
+                else
+                {
+                    throw new BizException("请设置正确的AzureCosmosDB数据库配置信息!");
+                }
+                DatabaseId = options.Database;
+                CollectionThroughput = options.CollectionThroughput;
+                ScanModel = options.ScanModel;
+                // InitializeDatabase().GetAwaiter().GetResult();
+            }
+            catch (CosmosException e)
+            {
+                Dispose(true);
+                throw new BizException(e.Message, 500, e.StackTrace);
+            }
+        }
+
+
+        public async Task InitializeDatabase()
+        {
+            try
+            {
+                database = await CosmosClient.CreateDatabaseIfNotExistsAsync(DatabaseId, CollectionThroughput);
+                FeedIterator<ContainerProperties> resultSetIterator = database.GetContainerQueryIterator<ContainerProperties>();
+                while (resultSetIterator.HasMoreResults)
+                {
+                    foreach (ContainerProperties container in await resultSetIterator.ReadNextAsync())
+                    {
+                        DocumentCollectionDict.TryAdd(container.Id, database.GetContainer(container.Id));
+                    }
+                }
+                //获取数据库所有的表
+                List<Type> types = ReflectorExtensions.GetAllTypeAsAttribute<CosmosDBAttribute>(ScanModel);
+                foreach (Type type in types)
+                {
+                    string PartitionKey = GetPartitionKey(type);
+                    string CollectionName = "";
+                    int RU = 0;
+                    IEnumerable<CosmosDBAttribute> attributes = type.GetCustomAttributes<CosmosDBAttribute>(true);
+                    if (!string.IsNullOrEmpty(attributes.First<CosmosDBAttribute>().Name))
+                    {
+                        CollectionName = attributes.First<CosmosDBAttribute>().Name;
+                    }
+                    else
+                    {
+                        CollectionName = type.Name;
+                    }
+                    if (attributes.First<CosmosDBAttribute>().RU > 400)
+                    {
+                        RU = attributes.First<CosmosDBAttribute>().RU;
+                    }
+                    else
+                    {
+                        RU = CollectionThroughput;
+                    }
+                    //如果表存在于数据则检查RU是否变动,如果不存在则执行创建DocumentCollection
+                    if (DocumentCollectionDict.TryGetValue(CollectionName, out Container collection))
+                    { //更新RU
+
+                        int? throughputResponse = await CosmosClient.GetDatabase(DatabaseId).GetContainer(collection.Id).ReadThroughputAsync();
+                        if (throughputResponse < RU)
+                        {
+                            await CosmosClient.GetDatabase(DatabaseId).GetContainer(collection.Id).ReplaceThroughputAsync(RU);
+                        }
+                    }
+                    else
+                    {
+                        ContainerProperties containerProperties = new ContainerProperties { Id = CollectionName };
+
+                        if (!string.IsNullOrEmpty(PartitionKey))
+                        {
+                            containerProperties.PartitionKeyPath = "/" + PartitionKey;
+                        }
+                        if (RU > CollectionThroughput)
+                        {
+                            CollectionThroughput = RU;
+                        }
+                        Container containerWithConsistentIndexing = await database.CreateContainerIfNotExistsAsync(containerProperties, throughput: CollectionThroughput);
+                        DocumentCollectionDict.TryAdd(CollectionName, containerWithConsistentIndexing);
+                    }
+                }
+            }
+            catch (CosmosException e)
+            {
+                throw new BizException(e.Message, 500, e.StackTrace);
+            }
+        }
+
+
+
+
+        private string GetPartitionKey<T>()
+        {
+            Type type = typeof(T);
+            return GetPartitionKey(type);
+        }
+        private string GetPartitionKey(Type type)
+        {
+            PropertyInfo[] properties = type.GetProperties();
+            List<PropertyInfo> attrProperties = new List<PropertyInfo>();
+            foreach (PropertyInfo property in properties)
+            {
+                if (property.Name.Equals("PartitionKey"))
+                {
+                    attrProperties.Add(property);
+                    break;
+                }
+                object[] attributes = property.GetCustomAttributes(true);
+                foreach (object attribute in attributes) //2.通过映射,找到成员属性上关联的特性类实例,
+                {
+                    if (attribute is PartitionKeyAttribute)
+                    {
+                        attrProperties.Add(property);
+                    }
+                }
+            }
+            if (attrProperties.Count <= 0)
+            {
+                throw new BizException(type.Name + "has no PartitionKey !");
+            }
+            else
+            {
+                if (attrProperties.Count == 1)
+                {
+                    return attrProperties[0].Name;
+                }
+                else { throw new BizException("PartitionKey can only be single!"); }
+            }
+        }
+
+
+        private async Task<Container> InitializeCollection<T>()
+        {
+            Type type = typeof(T);
+            string partitionKey = GetPartitionKey<T>();
+            string CollectionName;
+            IEnumerable<CosmosDBAttribute> attributes = type.GetCustomAttributes<CosmosDBAttribute>(true);
+            if (!string.IsNullOrEmpty(attributes.First<CosmosDBAttribute>().Name))
+            {
+                CollectionName = attributes.First<CosmosDBAttribute>().Name;
+            }
+            else
+            {
+                CollectionName = type.Name;
+            }
+            return await InitializeCollection(CollectionName, partitionKey);
+        }
+
+        private async Task<Container> InitializeCollection(string CollectionName, string PartitionKey)
+        {
+            /////内存中已经存在这个表则直接返回
+            if (DocumentCollectionDict.TryGetValue(CollectionName, out Container DocumentCollection))
+            {
+                return DocumentCollection;
+            }///如果没有则尝试默认创建
+            else
+            {
+                ContainerProperties containerProperties = new ContainerProperties { Id = CollectionName };
+                if (!string.IsNullOrEmpty(PartitionKey))
+                {
+                    containerProperties.PartitionKeyPath = "/" + PartitionKey;
+                }
+                Container containerWithConsistentIndexing = await database.CreateContainerIfNotExistsAsync(containerProperties, throughput: CollectionThroughput);
+                DocumentCollectionDict.TryAdd(CollectionName, containerWithConsistentIndexing);
+                return containerWithConsistentIndexing;
+            }
+        }
+
+
+        public async Task DeleteAll<T>(List<KeyValuePair<string, string>> ids) where T : ID
+        {
+            string partitionKey = GetPartitionKey<T>();
+            await Task.Run(() => Parallel.ForEach(ids, (item) =>
+            {
+                Task.WaitAll(DeleteAsync<T>(item.Value, item.Key));
+            }));
+        }
+
+        public async Task DeleteAll<T>(List<T> entities) where T : ID
+        {
+            string partitionKey = GetPartitionKey<T>();
+            Type type = typeof(T);
+            await Task.Run(() => Parallel.ForEach(entities, (item) =>
+            {
+                object o = type.GetProperty(partitionKey).GetValue(item, null);
+                Task.WaitAll(DeleteAsync<T>(item.id, o.ToString()));
+            }));
+        }
+        public async Task<T> DeleteAsync<T>(string id, string pk) where T : ID
+        {
+            Container container = await InitializeCollection<T>();
+            ItemResponse<T> response = await container.DeleteItemAsync<T>(id: id, partitionKey: new PartitionKey(pk));
+            return response.Resource;
+        }
+
+        public async Task<T> DeleteAsync<T>(T entity, string pk) where T : ID
+        {
+            Container container = await InitializeCollection<T>();
+            string partitionKey = GetPartitionKey<T>();
+            Type type = typeof(T);
+            object o = type.GetProperty(partitionKey).GetValue(entity, null);
+            ItemResponse<T> response = await container.DeleteItemAsync<T>(id: entity.id, partitionKey: new PartitionKey(o.ToString()));
+            return response.Resource;
+
+        }
+        //public async Task<T> DeleteAsync<T>(string id) where T : ID
+        //{
+        //    Container container = await InitializeCollection<T>();
+        //    ItemResponse<T> response = await container.DeleteItemAsync<T>(id: id, partitionKey: new PartitionKey(GetPartitionKey<T>()));
+        //    return response.Resource;
+        //}
+
+        public async Task<List<T>> FindAll<T>() where T : ID
+        {
+            Container container = await InitializeCollection<T>();
+            return await ResultsFromFeedIterator(container.GetItemQueryIterator<T>());
+
+        }
+        private async Task<List<T>> ResultsFromFeedIterator<T>(FeedIterator<T> query, int? maxItemCount = null)
+        {
+            List<T> results = new List<T>();
+            while (query.HasMoreResults)
+            {
+                foreach (T t in await query.ReadNextAsync())
+                {
+                    results.Add(t);
+                    if (results.Count == maxItemCount)
+                    {
+                        return results;
+                    }
+                }
+            }
+            return results;
+        }
+        private async Task<List<T>> ResultsFromFeedIterator<T>(FeedIterator<T> query, Func<List<T>, Task> batchAction, int itemsPerPage)
+        {
+            List<T> results = new List<T>();
+            while (query.HasMoreResults)
+            {
+                if (results.Count() >= itemsPerPage)
+                {
+                    await batchAction(results);
+                    results.Clear();
+                }
+
+                results.AddRange(await query.ReadNextAsync());
+            }
+
+            if (results.Count() > 0)
+            {
+                await batchAction(results);
+                results.Clear();
+            }
+
+            return results;
+        }
+        public async Task<List<dynamic>> FindByDict(string CollectionName, Dictionary<string, object> dict, int itemsPerPage = -1, int? maxItemCount = null, string partitionKey = null)
+        {
+            if (DocumentCollectionDict.TryGetValue(CollectionName, out Container container))
+            {
+                //StringBuilder sql = new StringBuilder("select value(c) from c");
+                //SQLHelper.GetSQL(dict, ref sql);
+                //CosmosDbQuery cosmosDbQuery = new CosmosDbQuery
+                //{
+                //    QueryText = sql.ToString()
+
+                //};
+                StringBuilder sql = new StringBuilder("select value(c) from c");
+                CosmosDbQuery cosmosDbQuery = SQLHelperParametric.GetSQL(dict, sql);
+                QueryRequestOptions queryRequestOptions = GetDefaultQueryRequestOptions(itemsPerPage: GetEffectivePageSize(itemsPerPage, maxItemCount));
+                FeedIterator<dynamic> query = container.GetItemQueryIterator<dynamic>(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: queryRequestOptions);
+                return await ResultsFromFeedIterator(query, maxItemCount);
+            }
+            else
+            {
+                throw new BizException("CollectionName named:" + CollectionName + " dose not exsit in Database!");
+            }
+
+        }
+
+        public async Task<List<dynamic>> FindCountByDict(string CollectionName, Dictionary<string, object> dict, int itemsPerPage = -1, int? maxItemCount = null, string partitionKey = null)
+        {
+            if (DocumentCollectionDict.TryGetValue(CollectionName, out Container container))
+            {
+                //StringBuilder sql = new StringBuilder("select  value count(c)  from c");
+                //SQLHelper.GetSQL(dict, ref sql);
+                //CosmosDbQuery cosmosDbQuery = new CosmosDbQuery
+                //{
+                //    QueryText = sql.ToString()
+
+                //};
+                StringBuilder sql = new StringBuilder("select  value count(c)  from c");
+                CosmosDbQuery cosmosDbQuery = SQLHelperParametric.GetSQL(dict, sql);
+                QueryRequestOptions queryRequestOptions = GetDefaultQueryRequestOptions(itemsPerPage: GetEffectivePageSize(itemsPerPage, maxItemCount));
+                FeedIterator<dynamic> query = container.GetItemQueryIterator<dynamic>(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: queryRequestOptions);
+                return await ResultsFromFeedIterator(query, maxItemCount);
+            }
+            else
+            {
+                throw new BizException("CollectionName named:" + CollectionName + " dose not exsit in Database!");
+            }
+        }
+
+        public async Task<List<T>> FindByParams<T>(Dictionary<string, object> dict, int itemsPerPage = -1, int? maxItemCount = null, string partitionKey = null) where T : ID
+        {
+            return await FindByDict<T>(dict, itemsPerPage, maxItemCount, partitionKey);
+        }
+        public async Task<List<T>> FindByDict<T>(Dictionary<string, object> dict, int itemsPerPage = -1, int? maxItemCount = null, string partitionKey = null) where T : ID
+        {
+
+            StringBuilder sql = new StringBuilder("select value(c) from c");
+            SQLHelper.GetSQL(dict, ref sql);
+            CosmosDbQuery cosmosDbQuery = new CosmosDbQuery
+            {
+                QueryText = sql.ToString()
+
+            };
+            QueryRequestOptions queryRequestOptions = GetDefaultQueryRequestOptions(itemsPerPage: GetEffectivePageSize(itemsPerPage, maxItemCount));
+            return await ResultsFromQueryAndOptions<T>(cosmosDbQuery, queryRequestOptions);
+        }
+
+        private async Task<List<T>> ResultsFromQueryAndOptions<T>(CosmosDbQuery cosmosDbQuery, QueryRequestOptions queryOptions, int? maxItemCount = null)
+        {
+            Container container = await InitializeCollection<T>();
+            FeedIterator<T> query = container.GetItemQueryIterator<T>(
+                queryDefinition: cosmosDbQuery.CosmosQueryDefinition,
+                requestOptions: queryOptions);
+
+            return await ResultsFromFeedIterator(query, maxItemCount);
+        }
+        private int GetEffectivePageSize(int itemsPerPage, int? maxItemCount)
+        {
+            return itemsPerPage == -1 ? maxItemCount ?? itemsPerPage : Math.Min(maxItemCount ?? itemsPerPage, itemsPerPage);
+        }
+        private QueryRequestOptions GetDefaultQueryRequestOptions(int? itemsPerPage = null,
+        int? maxBufferedItemCount = null,
+        int? maxConcurrency = null)
+        {
+            QueryRequestOptions queryRequestOptions = new QueryRequestOptions
+            {
+                MaxItemCount = itemsPerPage == -1 ? 1000 : itemsPerPage,
+                MaxBufferedItemCount = maxBufferedItemCount ?? 100,
+                MaxConcurrency = maxConcurrency ?? 50
+            };
+
+            return queryRequestOptions;
+        }
+        private async Task<List<T>> ResultsFromQueryAndOptions<T>(CosmosDbQuery cosmosDbQuery, Func<List<T>, Task> batchAction, QueryRequestOptions queryOptions)
+        {
+            Container container = await InitializeCollection<T>();
+            FeedIterator<T> query = container.GetItemQueryIterator<T>(
+                queryDefinition: cosmosDbQuery.CosmosQueryDefinition,
+                requestOptions: queryOptions);
+
+            return await ResultsFromFeedIterator(query, batchAction, queryOptions.MaxItemCount ?? 0);
+        }
+
+
+
+        private QueryRequestOptions GetQueryRequestOptions(int itemsPerPage)
+        {
+            QueryRequestOptions queryRequestOptions = new QueryRequestOptions
+            {
+                MaxItemCount = itemsPerPage
+            };
+
+            return queryRequestOptions;
+        }
+        public async Task<List<T>> FindLinq<T>(Expression<Func<T, bool>> query = null, Expression<Func<T, object>> order = null, bool isDesc = false, int itemsPerPage = -1, int? maxItemCount = null) where T : ID
+        {
+            //QueryRequestOptions queryRequestOptions = GetQueryRequestOptions(itemsPerPage);
+            QueryRequestOptions queryRequestOptions = GetDefaultQueryRequestOptions(itemsPerPage: GetEffectivePageSize(itemsPerPage, maxItemCount));
+            FeedIterator<T> feedIterator;
+            Container container = await InitializeCollection<T>();
+
+            if (query == null)
+            {
+                if (order != null)
+                {
+                    if (isDesc)
+                    {
+                        feedIterator = container
+                       .GetItemLinqQueryable<T>(requestOptions: queryRequestOptions).OrderByDescending(order)
+                       .ToFeedIterator();
+                    }
+                    else
+                    {
+                        feedIterator = container
+                       .GetItemLinqQueryable<T>(requestOptions: queryRequestOptions).OrderBy(order)
+                       .ToFeedIterator();
+                    }
+                }
+                else
+                {
+                    feedIterator = container
+                   .GetItemLinqQueryable<T>(requestOptions: queryRequestOptions)
+                   .ToFeedIterator();
+                }
+            }
+            else
+            {
+                if (order != null)
+                {
+                    if (isDesc)
+                    {
+                        feedIterator = container
+                        .GetItemLinqQueryable<T>(requestOptions: queryRequestOptions)
+                        .Where(query).OrderByDescending(order)
+                        .ToFeedIterator();
+                    }
+                    else
+                    {
+                        feedIterator = container
+                    .GetItemLinqQueryable<T>(requestOptions: queryRequestOptions)
+                    .Where(query).OrderBy(order)
+                    .ToFeedIterator();
+                    }
+                }
+                else
+                {
+                    feedIterator = container
+                    .GetItemLinqQueryable<T>(requestOptions: queryRequestOptions)
+                    .Where(query)
+                    .ToFeedIterator();
+                }
+            }
+            return await ResultsFromFeedIterator<T>(feedIterator);
+        }
+
+        public async Task<List<T>> FindSQL<T>(string sql, Dictionary<string, object> Parameters = null, int itemsPerPage = -1, int? maxItemCount = null) where T : ID
+        {
+            Container container = await InitializeCollection<T>();
+            QueryRequestOptions queryOptions = GetQueryRequestOptions(GetEffectivePageSize(itemsPerPage, maxItemCount));
+            if (Parameters != null)
+            {
+                CosmosDbQuery cosmosDbQuery = new CosmosDbQuery
+                {
+                    QueryText = sql,
+                    Parameters = Parameters
+                };
+                FeedIterator<T> feedIterator = container
+                .GetItemQueryIterator<T>(cosmosDbQuery.CosmosQueryDefinition, requestOptions: queryOptions);
+                return await ResultsFromFeedIterator(feedIterator);
+            }
+            else
+            {
+                QueryDefinition queryDefinition = new QueryDefinition(sql);
+                return await ResultsFromFeedIterator<T>(container.GetItemQueryIterator<T>(queryDefinition));
+            }
+        }
+
+        //public async Task<List<T>> FindSQL<T>(string sql, bool isPK) where T : ID
+        //{
+        //    Container container = await InitializeCollection<T>();
+        //    QueryDefinition queryDefinition = new QueryDefinition(sql);
+        //    return await ResultsFromFeedIterator<T>(container.GetItemQueryIterator<T>(queryDefinition));
+        //}
+
+        public async Task<T> ReplaceObject<T>(T entity) where T : ID
+        {
+            Container container = await InitializeCollection<T>();
+            ItemResponse<T> response = await container.ReplaceItemAsync(item: entity, id: entity.id);
+            if (response.StatusCode.Equals(HttpStatusCode.OK))
+            {
+                return response.Resource;
+            }
+            else { throw new BizException("error"); }
+
+        }
+
+        //public async Task<T> ReplaceObject<T>(T entity, string key, string partitionKey) where T : ID
+        //{
+        //    Container container = await InitializeCollection<T>();
+        //    ItemResponse<T> response = await container.ReplaceItemAsync(item: entity, id: entity.id);
+        //    if (response.StatusCode.Equals(HttpStatusCode.OK))
+        //    {
+        //        return response.Resource;
+        //    }
+        //    else { throw new BizException("error"); }
+
+        //}
+
+        public async Task<T> Save<T>(T entity) where T : ID
+        {
+            try
+            {
+                Container container = await InitializeCollection<T>();
+                ItemResponse<T> response = await container.CreateItemAsync<T>(entity);
+                return response.Resource;
+            }
+            catch (Exception e)
+            {
+                throw new BizException(e.Message);
+            }
+        }
+
+        public async Task<List<T>> SaveAll<T>(List<T> enyites) where T : ID
+        {
+
+            await Task.Run(() => Parallel.ForEach(enyites, (item) =>
+            {
+                Task.WaitAll(Save(item));
+            }));
+            return enyites;
+        }
+
+        public async Task<T> Update<T>(T entity) where T : ID
+        {
+            Container container = await InitializeCollection<T>();
+            ItemResponse<T> response = await container.UpsertItemAsync(entity);
+            return response.Resource;
+        }
+
+        public async Task<List<T>> UpdateAll<T>(List<T> entities) where T : ID
+        {
+            await Task.Run(() => Parallel.ForEach(entities, (item) =>
+            {
+                Task.WaitAll(Update(item));
+            }));
+            return entities;
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                CosmosClient?.Dispose();
+            }
+        }
+
+        public async Task<T> FindById<T>(string id) where T : ID
+        {
+            Container container = await InitializeCollection<T>();
+            CosmosDbQuery cosmosDbQuery = new CosmosDbQuery
+            {
+                QueryText = @"SELECT *
+                            FROM    c 
+                            WHERE   c.id = @id",
+                Parameters = new Dictionary<string, object>
+                 {
+
+                    { "@id",id}
+                }
+            };
+            FeedIterator<T> feedIterator = container
+               .GetItemQueryIterator<T>(cosmosDbQuery.CosmosQueryDefinition);
+            return (await ResultsFromFeedIterator(feedIterator)).SingleOrDefault();
+        }
+
+        public async Task<T> FindByIdPk<T>(string id, string pk) where T : ID
+        {
+            Container container = await InitializeCollection<T>();
+            ItemResponse<T> response = await container.ReadItemAsync<T>(id: id, partitionKey: new PartitionKey(pk));
+            return response.Resource;
+        }
+
+
+        public async Task<List<T>> FindByDictTest<T>(Dictionary<string, object> dict, int itemsPerPage = 1, int? maxItemCount = 1, string partitionKey = null) where T : ID
+        {
+            //Container container = await InitializeCollection<T>();
+            StringBuilder sql = new StringBuilder("select value(c) from c");
+            CosmosDbQuery cosmosDbQuery = SQLHelperParametric.GetSQL(dict, sql);
+            QueryRequestOptions queryRequestOptions = GetDefaultQueryRequestOptions(itemsPerPage: GetEffectivePageSize(itemsPerPage, maxItemCount));
+
+            //FeedIterator<T> feedIterator = container
+            //   .GetItemQueryIterator<T>(cosmosDbQuery.CosmosQueryDefinition);
+            // return (await ResultsFromFeedIterator(feedIterator)).SingleOrDefault();
+
+
+            return await ResultsFromQueryAndOptions<T>(cosmosDbQuery, queryRequestOptions, maxItemCount);
+        }
+    }
+}

+ 46 - 0
TEAMModelOS.SDK/Module/AzureCosmosDBV3/AzureCosmosDBV3ServiceCollectionExtensions.cs

@@ -0,0 +1,46 @@
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using TEAMModelOS.SDK.Module.AzureCosmosDB.Configuration;
+using TEAMModelOS.SDK.Module.AzureCosmosDB.Interfaces;
+
+namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
+{
+
+        public static class AzureCosmosDBServiceCollectionExtensions
+        {
+            /// <summary>
+            /// 
+            /// </summary>
+            /// <param name="services"></param>
+            /// <returns></returns>
+            private static AzureCosmosDBServiceBuilder AddCosmosDBServerBuilder(this IServiceCollection services)
+            {
+                return new AzureCosmosDBServiceBuilder(services);
+            }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            /// <param name="services"></param>
+            /// <returns></returns>
+            public static AzureCosmosDBServiceBuilder AddAzureCosmosDBV3(this IServiceCollection services)
+            {
+                var builder = services.AddCosmosDBServerBuilder();
+                services.AddSingleton<IAzureCosmosDBV3Repository, AzureCosmosDBV3Repository>();
+                return builder;
+            }
+            /// <summary>
+            /// 
+            /// </summary>
+            /// <param name="builder"></param>
+            /// <param name="_connectionString"></param>
+            /// <returns></returns>
+            public static AzureCosmosDBServiceBuilder AddCosmosDBConnection(this AzureCosmosDBServiceBuilder builder, AzureCosmosDBOptions databaseOptions)
+            {
+                builder.Services.AddSingleton(databaseOptions);
+                return builder;
+            }
+        }
+}

+ 58 - 0
TEAMModelOS.SDK/Module/AzureCosmosDBV3/CosmosDBV3ClientSingleton.cs

@@ -0,0 +1,58 @@
+using Microsoft.Azure.Cosmos;
+using Microsoft.Azure.Cosmos.Fluent;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
+{
+    public class CosmosDBV3ClientSingleton
+    {
+        private static string _connectionUrl;
+        private static string _connectionKey;
+        private CosmosClient CosmosClient;
+
+        private CosmosDBV3ClientSingleton() { }
+
+
+
+        public CosmosClient GetCosmosDBClient()
+        {
+            if (CosmosClient != null)
+            {
+                return CosmosClient;
+            }
+            else
+            {
+                getInstance(_connectionUrl, _connectionKey);
+                return CosmosClient;
+            }
+        }
+
+        public static CosmosDBV3ClientSingleton getInstance(string connectionUrl, string connectionKey)
+        {
+            _connectionUrl = connectionUrl;
+            _connectionKey = connectionKey;
+            return SingletonInstance.instance;
+        }
+
+        private static class SingletonInstance
+        {
+            public static CosmosDBV3ClientSingleton instance = new CosmosDBV3ClientSingleton()
+            {
+                // CosmosClient    =new CosmosClient(_connectionUrl, _connectionKey, new CosmosClientOptions() { AllowBulkExecution = true } )
+                CosmosClient = new CosmosClientBuilder(_connectionUrl, _connectionKey).
+                WithBulkExecution(true).WithConnectionModeDirect().
+                //WithConnectionModeDirect().
+                WithCustomSerializer(new SystemTextJsonCosmosSerializer(new System.Text.Json.JsonSerializerOptions()))
+                .Build()
+                //CosmosClient = new CosmosClient(_connectionUrl, _connectionKey)
+            };
+            //private static readonly ConnectionPolicy ConnectionPolicy = new ConnectionPolicy
+            //{
+            //    ConnectionMode = ConnectionMode.Direct,
+            //    ConnectionProtocol = Protocol.Tcp
+            //};
+        }
+    }
+}

+ 45 - 0
TEAMModelOS.SDK/Module/AzureCosmosDBV3/CosmosDbQuery.cs

@@ -0,0 +1,45 @@
+using Microsoft.Azure.Cosmos;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
+{
+   public class CosmosDbQuery
+    {
+        public string QueryText { get; set; }
+
+        public Dictionary<string, object> Parameters { get; set; }
+
+        public QueryDefinition CosmosQueryDefinition
+        {
+            get
+            {
+                QueryDefinition queryDefinition = new QueryDefinition(QueryText);
+
+                if (Parameters != null)
+                {
+                    foreach (var parameter in Parameters)
+                    {
+                        queryDefinition = queryDefinition.WithParameter(parameter.Key, parameter.Value);
+                    }
+                }
+
+                return queryDefinition;
+            }
+        }
+
+        public CosmosDbQuery() { }
+
+        public CosmosDbQuery(string queryText)
+        {
+            QueryText = queryText;
+        }
+
+        public CosmosDbQuery(string queryText, Dictionary<string, object> parameters)
+        {
+            QueryText = queryText;
+            Parameters = parameters;
+        }
+    }
+}

+ 69 - 0
TEAMModelOS.SDK/Module/AzureCosmosDBV3/IAzureCosmosDBV3Repository.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
+{
+    public interface IAzureCosmosDBV3Repository
+    {
+
+        Task<T> Save<T>(T entity) where T : ID;
+        Task<List<T>> SaveAll<T>(List<T> enyites) where T : ID;
+        Task<T> DeleteAsync<T>(T entity, string pk) where T : ID;
+        Task<T> DeleteAsync<T>(string id, string pk) where T : ID;
+        Task DeleteAll<T>(List<T> entities) where T : ID;
+        Task DeleteAll<T>(List<KeyValuePair<string, string>> ids) where T : ID;
+        Task<T> Update<T>(T entity) where T : ID;
+        Task<List<T>> UpdateAll<T>(List<T> entities) where T : ID;
+        Task<T> ReplaceObject<T>(T entity) where T : ID;
+
+        Task<T> FindById<T>(string id) where T : ID;
+        Task<T> FindByIdPk<T>(string id, string pk) where T : ID;
+        // Task<string> ReplaceObject<T>(T entity, string key, string partitionKey) where T : ID;
+        Task<List<T>> FindAll<T>() where T : ID;
+        /// <summary>
+        /// QueryText = @"SELECT *
+        //            FROM    c 
+        //            WHERE   c.documentType = @documentType 
+        //                    AND c.id = @id",
+        //Parameters = new[]
+        //{
+        //    new CosmosDbQueryParameter("@documentType", GetDocumentType<T>()),
+        //    new CosmosDbQueryParameter("@id", id)
+        //}
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="sql"></param>
+        /// <param name="Parameters"></param>
+        /// <returns></returns>
+        Task<List<T>> FindSQL<T>(string sql, Dictionary<string, object> Parameters = null, int itemsPerPage = -1, int? maxItemCount = null) where T : ID;
+        //Task<List<T>> FindSQL<T>(string sql, bool isPK) where T : ID;
+
+        /// <summary>
+        /////正确的代码
+        //Expression<Func<QuestionFeed, bool>> predicate = null;
+        //      query = f =>  1==1;
+        //    query= query.And(x =>x.Address.City== "Seattle3");
+        //    query= query.Or(x => x.id== "Andersen.1");
+        //    query = query.And(x => x.Parents.Where(y => y.FirstName == "Thomas1").Any()) ;
+        //    Expression<Func<Family, object>> order = null;
+        //order = f => f.id;
+        //_questionFeedRepository.Entities.Where(predicate);
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="itemsPerPage"></param>
+        /// <param name="query"></param>
+        /// <returns></returns>
+        Task<List<T>> FindLinq<T>(Expression<Func<T, bool>> query = null, Expression<Func<T, object>> order = null, bool isDesc = false, int itemsPerPage = -1, int? maxItemCount = null) where T : ID;
+        Task<List<T>> FindByParams<T>(Dictionary<string, object> dict, int itemsPerPage = -1, int? maxItemCount = null, string partitionKey = null) where T : ID;
+        Task<List<T>> FindByDict<T>(Dictionary<string, object> dict, int itemsPerPage = -1, int? maxItemCount = null, string partitionKey = null) where T : ID;
+        Task<List<dynamic>> FindByDict(string CollectionName, Dictionary<string, object> dict, int itemsPerPage = -1, int? maxItemCount = null, string partitionKey = null);
+        Task<List<dynamic>> FindCountByDict(string CollectionName, Dictionary<string, object> dict, int itemsPerPage = -1, int? maxItemCount = null, string partitionKey = null);
+        Task InitializeDatabase();
+        Task<List<T>> FindByDictTest<T>(Dictionary<string, object> dict, int itemsPerPage = -1, int? maxItemCount = null, string partitionKey = null) where T : ID;
+
+
+    }
+}

+ 11 - 0
TEAMModelOS.SDK/Module/AzureCosmosDBV3/ID.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
+{
+    public interface ID
+    {
+        string id { get; set; }
+    }
+}

+ 139 - 0
TEAMModelOS.SDK/Module/AzureCosmosDBV3/PredicateExtensions.cs

@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
+{
+    /// <summary>
+    //
+    /*
+               Expression<Func<UserInfo, bool>> exp = x => x.Status == (int)BizConst.UserStatus.Active;  
+               if(parameters.IsAuthenticated)
+               {
+                   exp = exp.And(x => x.IdentityAuth == (int) BizConst.IdentityAuthStatus.Authed && x.CareerAuth == (int) BizConst.GlobalCareerStatus.Authed);
+               }
+               if(parameters.IsVip)
+               {
+                   exp = exp.And(x => x.Vip != (int) BizConst.VipTag.NoVip);
+               }*/
+    /// </summary>
+    public static class PredicateExtensions
+    {
+        ///// <summary>
+        ///// 机关函数应用True时:单个AND有效,多个AND有效;单个OR无效,多个OR无效;混应时写在AND后的OR有效。即,设置为True时所有or语句应该放在and语句之后,否则无效
+        ///// </summary>
+        //public static Expression<Func<T, bool>> True<T>() { return f => true; }
+
+        ///// <summary>
+        ///// 机关函数应用False时:单个AND无效,多个AND无效;单个OR有效,多个OR有效;混应时写在OR后面的AND有效。 即,设置为False时所有or语句应该放在and语句之前,否则无效
+        ///// </summary>
+        //public static Expression<Func<T, bool>> False<T>() { return f => false; }
+
+        //public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expression1,
+        //   Expression<Func<T, bool>> expression2)
+        //{
+        //    var invokedExpression = Expression.Invoke(expression2, expression1.Parameters
+        //            .Cast<Expression>());
+
+        //    return Expression.Lambda<Func<T, bool>>(Expression.Or(expression1.Body, invokedExpression),
+        //    expression1.Parameters);
+        //}
+
+        //public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1,
+        //      Expression<Func<T, bool>> expression2)
+        //{
+        //    var invokedExpression = Expression.Invoke(expression2, expression1.Parameters
+        //         .Cast<Expression>());
+
+        //    return Expression.Lambda<Func<T, bool>>(Expression.And(expression1.Body,
+        //           invokedExpression), expression1.Parameters);
+
+        //}
+
+
+        /// <summary>
+        /// 机关函数应用True时:单个AND有效,多个AND有效;单个OR无效,多个OR无效;混应时写在AND后的OR有效。即,设置为True时所有or语句应该放在and语句之后,否则无效
+        /// </summary>
+        public static Expression<Func<T, bool>> BaseAnd<T>() { return f => true; }
+        /// <summary>
+        /// 机关函数应用False时:单个AND无效,多个AND无效;单个OR有效,多个OR有效;混应时写在OR后面的AND有效。 即,设置为False时所有or语句应该放在and语句之前,否则无效
+        /// </summary>
+        public static Expression<Func<T, bool>> BaseOr<T>() { return f => false; }
+
+        public static Expression<Func<T, bool>> Or<T>(
+            this Expression<Func<T, bool>> expr1,
+            Expression<Func<T, bool>> expr2)
+        {
+            var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
+            return Expression.Lambda<Func<T, bool>>
+                  (Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
+        }
+
+        public static Expression<Func<T, bool>> And<T>(
+            this Expression<Func<T, bool>> expr1,
+            Expression<Func<T, bool>> expr2)
+        {
+            var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
+            return Expression.Lambda<Func<T, bool>>
+                  (Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
+        }
+
+        public static Expression Replace(this Expression expression,
+        Expression searchEx, Expression replaceEx)
+        {
+            return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
+        }
+
+        public static Expression<Func<T, bool>> CombineOrPreicatesWithAndPredicates<T>(this Expression<Func<T, bool>> combinedPredicate,
+            Expression<Func<T, bool>> andPredicate, Expression<Func<T, bool>> orPredicate)
+        {
+            combinedPredicate = combinedPredicate ?? BaseAnd<T>();
+            if (andPredicate != null && orPredicate != null)
+            {
+                andPredicate = andPredicate.And(orPredicate);
+                combinedPredicate = combinedPredicate.And(andPredicate);
+            }
+            else if (orPredicate != null)
+            {
+                combinedPredicate = combinedPredicate.And(orPredicate);
+            }
+            else
+            {
+                combinedPredicate = combinedPredicate.And(andPredicate);
+            }
+            return combinedPredicate;
+        }
+
+        public static void AddToPredicateTypeBasedOnIfAndOrOr<T>(ref Expression<Func<T, bool>> andPredicate,
+            ref Expression<Func<T, bool>> orPredicate, Expression<Func<T, bool>> newExpression, bool isAnd)
+        {
+            if (isAnd)
+            {
+                andPredicate = andPredicate ?? BaseAnd<T>();
+                andPredicate = andPredicate.And(newExpression);
+            }
+            else
+            {
+                orPredicate = orPredicate ?? BaseOr<T>();
+                orPredicate = orPredicate.Or(newExpression);
+            }
+        }
+    }
+    internal class ReplaceVisitor : ExpressionVisitor
+    {
+        private readonly Expression from, to;
+
+        public ReplaceVisitor(Expression from, Expression to)
+        {
+            this.from = from;
+            this.to = to;
+        }
+
+        public override Expression Visit(Expression node)
+        {
+            return node == from ? to : base.Visit(node);
+        }
+    }
+}

+ 819 - 0
TEAMModelOS.SDK/Module/AzureCosmosDBV3/SQLHelperParametric.cs

@@ -0,0 +1,819 @@
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
+{
+    public class SQLHelperParametric
+    {
+        static readonly string[] LogicOpers = new string[] { " and ", " or " };
+        static readonly string[] CompareOpers = new string[] { " > ", " < ", " <= ", " >= ", " = ", " != ", " like ", " not like ", " in " };
+
+
+        public static void ReplaceKeyWords(ref StringBuilder sql)
+        {
+            sql.Replace(".order.", "['order'].");
+            sql.Replace(".order ", "['order'] ");
+
+            sql.Replace(".group.", "['group'].");
+            sql.Replace(".group ", "['group'] ");
+
+            sql.Replace(".end.", "['end'].");
+            sql.Replace(".end ", "['end'] ");
+
+            sql.Replace(".having.", "['having'].");
+            sql.Replace(".having ", "['having'] ");
+        }
+
+        public static CosmosDbQuery GetSQL(Dictionary<string, object> dict, StringBuilder sql)
+        {
+
+            if (dict != null)
+            {
+                Dictionary<string, object> parmeters = new Dictionary<string, object>();
+
+                int offsetNum = 0;
+                int limitNum = 0;
+                bool pageBool = false;
+                GetPageNum(dict, ref offsetNum, ref limitNum, ref pageBool);
+
+                //处理顺序
+                Stack<KeyValuePair<string, object>> stack = new Stack<KeyValuePair<string, object>>();
+
+                foreach (string item in dict.Keys)
+                {
+                    if (item.EndsWith(".|"))
+                    {
+                        stack.Push(new KeyValuePair<string, object>(item, dict[item]));
+                    }
+
+                }
+                foreach (string item in dict.Keys)
+                {
+                    if (!item.EndsWith(".|"))
+                    {
+                        stack.Push(new KeyValuePair<string, object>(item, dict[item]));
+                    }
+
+                }
+
+
+                string Join = " join ";
+                string instring = " in ";
+                Dictionary<string, string> keyValues = new Dictionary<string, string>();
+                StringBuilder WhereString = new StringBuilder();
+                int heada = 0;
+                string[] sqlHead = new string[] { "A", "B", "C", "D", "E", "F" };
+                int kslength = 0;
+                int logicOperNum = 0;
+                bool keyListValueList = true;
+                //string distinctHead = "select distinct value(c) from c ";
+
+
+                int stackCount = stack.Count;
+                //foreach (KeyValuePair<string, object> item in newDict)
+                for (int k = 0; k < stackCount; k++)
+                {
+                    KeyValuePair<string, object> item = stack.Pop();
+                    bool isLikeSQL = false;
+                    if (item.Key.StartsWith("$.") || item.Key.StartsWith("!$."))
+                    {
+                        isLikeSQL = true;
+                    }
+
+
+                    string key = item.Key;
+                    string[] keyHead = key.Split(".");
+                    int index = 0;
+                    int compareOper = 4;
+                    int logicOper = 0;
+
+                    if (key.EndsWith(".&"))
+                    {
+                        logicOper = (int)LogicOper.and;
+                        key = key.Replace(".&", "");
+                    }
+                    else if (key.EndsWith(".|"))
+                    {
+                        logicOper = (int)LogicOper.or;
+                        key = key.Replace(".|", "");
+                    }
+                    CompareOperSwitch(keyHead[0], ref key, ref compareOper);
+                    string[] keyBody = key.Split("[*]");
+                    if (keyBody.Length > 1)
+                    {
+                        key = key.Replace("[*].", "");
+                        key = key.Replace(".", "");
+
+                        kslength += keyBody.Length;
+                        if (kslength < (7 + heada))
+                        {
+                            StringBuilder sqlitem = new StringBuilder();
+                            for (int i = 0; i < keyBody.Length - 1; i++)
+                            {
+                                //Console.WriteLine(ks[i]);
+                                if (i == 0)
+                                {
+                                    sqlitem.Append(Join);
+                                    string a = sqlHead[heada] + index;
+                                    sqlitem.Append(a + " ");
+                                    //keyValues.Add(ks[i], a);
+                                    keyValues[keyBody[i]] = a;
+                                    sqlitem.Append(instring);
+                                    sqlitem.Append("c.");
+                                    sqlitem.Append(keyBody[i]);
+                                }
+                                else
+                                {
+                                    sqlitem.Append(Join);
+                                    string a = sqlHead[heada] + index;
+                                    sqlitem.Append(a + " ");
+                                    //keyValues.Add(ks[i], a);
+                                    keyValues[keyBody[i]] = a;
+                                    sqlitem.Append(instring);
+                                    sqlitem.Append(keyValues[keyBody[i - 1]]);
+                                    sqlitem.Append(keyBody[i]);
+                                }
+                                index += 1;
+                            }
+                            sql.Append(sqlitem);
+                            string s = "";
+                            if (isLikeSQL)
+                            {
+                                if (item.Value is JArray array)
+                                {
+                                    s = ValueIsLike(sqlHead[heada] + (keyBody.Length - 2) + keyBody[index] + "", key, array, LogicOpers[logicOper], logicOperNum, compareOper, ref keyListValueList);
+                                }
+                                else if (item.Value is IEnumerable enumerable && !(item.Value is String))
+                                {
+                                    s = ValueIsLike(sqlHead[heada] + (keyBody.Length - 2) + keyBody[index] + "", key, enumerable, LogicOpers[logicOper], logicOperNum, compareOper, ref keyListValueList);
+                                }
+                                else if (item.Value is JsonElement jsonElement1)
+                                {
+                                    if (jsonElement1.ValueKind is JsonValueKind.Object)
+                                    {
+
+                                        string compareOperBool = " true ";
+                                        compareOperBool = CompareBoolSwitch(compareOper);
+                                        string logicOperString = " and ";
+                                        if (logicOperNum != 0) logicOperString = LogicOpers[logicOper];
+                                        s = logicOperString + "Contains(" + sqlHead[heada] + (keyBody.Length - 2) + keyBody[index] + " , \'" + item.Value.ToString() + "\') = " + compareOperBool + " ";
+                                    }
+                                    else
+                                    {
+                                        s = ValueIsLike(sqlHead[heada] + (keyBody.Length - 2) + keyBody[index] + "", key, jsonElement1, LogicOpers[logicOper], logicOperNum, compareOper, ref keyListValueList);
+                                    }
+
+                                }
+                                else
+                                {
+                                    s = ValueIsLike(sqlHead[heada] + (keyBody.Length - 2) + keyBody[index] + "", key, item.Value, LogicOpers[logicOper], logicOperNum, compareOper, ref keyListValueList);
+                                }
+                            }
+                            else
+                            {
+                                s = ValueNotLike(sqlHead[heada] + (keyBody.Length - 2) + keyBody[index] + "", key, item.Value, LogicOpers[logicOper], logicOperNum, compareOper, ref keyListValueList);
+                            }
+                            WhereString.Append(s);
+
+                            if (keyListValueList)
+                            {
+                                sql = sql.Replace("select ", "select distinct ");
+                            }
+                        }
+                        else
+                        {
+                            //throw new BizException("数组总共深度不能超过5层", ResponseCode.PARAMS_ERROR);
+                        }
+                        heada += 1;
+
+                    }
+                    else
+                    {
+
+                        string itemKey = item.Key.Replace(".", "");
+                        WhereString.Append(KeyNotElement(dict[item.Key], item.Key, itemKey, LogicOpers[logicOper], logicOperNum, compareOper));
+
+                    }
+                    // heada += 1;
+                    logicOperNum += 1;
+                }
+                sql.Append(" where 1=1 ").Append(WhereString);
+                if (pageBool)
+                {
+                    sql.Append(" OFFSET " + offsetNum + " LIMIT " + limitNum);
+                }
+
+                ReplaceKeyWords(ref sql);
+                //sql = sql.Replace("[*].", "");
+
+                parmeters = GetParmeter(dict, parmeters);
+
+                CosmosDbQuery cosmosDbQuery = new CosmosDbQuery
+                {
+                    QueryText = sql.ToString(),
+                    Parameters = parmeters
+                };
+
+                return cosmosDbQuery;
+            }
+
+            return null;
+        }
+
+        private static void GetPageNum(Dictionary<string, object> dict, ref int offsetNum, ref int limitNum, ref bool pageBool)
+        {
+            dict.TryGetValue("OFFSET", out object offset);
+            dict.Remove("OFFSET");
+            dict.TryGetValue("LIMIT", out object limit);
+            dict.Remove("LIMIT");
+            if (offset != null && limit != null)
+            {
+                pageBool = true;
+                offsetNum = int.Parse(offset.ToString());
+                limitNum = int.Parse(limit.ToString());
+            }
+        }
+
+        private static void CompareOperSwitch(string keyHead, ref string key, ref int compareOper)
+        {
+            switch (keyHead)
+            {
+                case ">":
+                    compareOper = (int)CompareOper.moreThan;
+                    key = key.Replace(">.", "");
+                    break;
+                case "<":
+                    compareOper = (int)CompareOper.lessThan;
+                    key = key.Replace("<.", "");
+                    break;
+                case "<=":
+                    compareOper = (int)CompareOper.notMoreThan;
+                    key = key.Replace("<=.", "");
+                    break;
+                case ">=":
+                    compareOper = (int)CompareOper.notLessThan;
+                    key = key.Replace(">=.", "");
+                    break;
+                case "=":
+                    compareOper = (int)CompareOper.equal;
+                    key = key.Replace("=.", "");
+                    break;
+                case "!=":
+                    compareOper = (int)CompareOper.notEqual;
+                    key = key.Replace("!=.", "");
+                    break;
+                case "$":
+                    compareOper = (int)CompareOper.like;
+                    key = key.Replace("$.", "");
+                    break;
+                case "!$":
+                    compareOper = (int)CompareOper.notLike;
+                    key = key.Replace("!$.", "");
+                    break;
+                default:
+                    compareOper = 4;
+                    break;
+            }
+        }
+
+        private static string ValueNotLike(string key, string key1, object value, string logicOperParams, int logicOperNum, int compareOperNum, ref bool keyListValueList)
+        {
+
+            string logicOper = " and ";
+            string compareOper = " = ";
+            if (compareOperNum != 4) compareOper = CompareOpers[compareOperNum];
+            if (logicOperNum != 0) logicOper = logicOperParams;
+            StringBuilder sql = new StringBuilder(logicOper + key + " in (");
+            if (value is JArray array)
+            {
+                int aa = 0;
+                foreach (JValue obja in array)
+                {
+                    sql.Append(" @" + key1 + aa + " ,");
+                    //if (obja.Value is string a)
+                    //{
+                    //    sql.Append("\'" + a + "\',");
+                    //}
+                    //if (obja.Value is int b)
+                    //{
+                    //    sql.Append(b + ",");
+                    //}
+                    //if (obja.Value is double c)
+                    //{
+                    //    sql.Append(c + ",");
+                    //}
+                    //if (obja.Value is bool d)
+                    //{
+                    //    sql.Append(d + ",");
+                    //}
+                    //if (obja.Value is long e)
+                    //{
+                    //    sql.Append(e + ",");
+                    //}
+                    //if (obja.Value is DateTime f)
+                    //{
+                    //    sql.Append(f + ",");
+                    //}
+                    aa++;
+                }
+                string sqls = sql.ToString().Substring(0, sql.Length - 1);
+                sqls += " ) ";
+                return sqls;
+            }
+            else if (value is IEnumerable enumerable && !(value is String))
+            {
+                int aa = 0;
+                foreach (object obja in enumerable)
+                {
+                    sql.Append(" @" + key1 + aa + " ,");
+                    //if (obja is string a)
+                    //{
+                    //    sql.Append("\'" + a + "\',");
+                    //}
+                    //if (obja is int b)
+                    //{
+                    //    sql.Append(" " + b + " ,");
+
+                    //}
+                    //if (obja is double c)
+                    //{
+                    //    sql.Append(" " + c + " ,");
+                    //}
+                    //if (obja is bool d)
+                    //{
+                    //    sql.Append(" " + d + " ,");
+
+                    //}
+                    //if (obja is long e)
+                    //{
+                    //    sql.Append(" " + e + " ,");
+                    //}
+                    //if (obja is DateTime f)
+                    //{
+                    //    sql.Append(" " + f + " ,");
+                    //}
+                    aa++;
+                }
+                string sqls = sql.ToString().Substring(0, sql.Length - 1);
+                sqls += ") ";
+                return sqls;
+            }
+            else if (value is JsonElement jsonElement)
+            {
+                if (jsonElement.ValueKind is JsonValueKind.Array)
+                {
+                    int aa = 0;
+                    foreach (JsonElement obja in jsonElement.EnumerateArray().ToArray())
+                    {
+                        sql.Append(" @" + key1 + aa + " ,");
+
+                        //if (obja.ValueKind is JsonValueKind.String)
+                        //{
+                        //    sql.Append("\'" + obja.ToString() + "\',");
+                        //}
+                        //if (obja.ValueKind is JsonValueKind.Number)
+                        //{
+                        //    sql.Append(" " + int.Parse(obja.ToString()) + " ,");
+                        //}
+                        //if (obja.ValueKind is JsonValueKind.True)
+                        //{
+                        //    sql.Append(" " + bool.Parse(obja.ToString()) + " ,");
+                        //}
+                        //if (obja.ValueKind is JsonValueKind.False)
+                        //{
+                        //    sql.Append(" " + bool.Parse(obja.ToString()) + " ,");
+                        //}
+                        aa++;
+                    }
+                }
+                else
+                {
+                    return logicOper + key + compareOper + " @" + key1 + " ";
+
+                    //if (jsonElement.ValueKind is JsonValueKind.String)
+                    //{
+                    //    return logicOper + key + compareOper + "\'" + value.ToString() + "\'";
+                    //}
+                    //if (jsonElement.ValueKind is JsonValueKind.Number)
+                    //{
+                    //    return logicOper + key + compareOper + double.Parse(value.ToString());
+                    //}
+                    //if (jsonElement.ValueKind is JsonValueKind.True)
+                    //{
+                    //    return logicOper + key + compareOper + bool.Parse(value.ToString());
+                    //}
+                    //if (jsonElement.ValueKind is JsonValueKind.False)
+                    //{
+                    //    return logicOper + key + compareOper + bool.Parse(value.ToString());
+                    //}
+
+                }
+
+                string sqls = sql.ToString().Substring(0, sql.Length - 1);
+                sqls += " ) ";
+                return sqls;
+            }
+            else
+            {
+                Type s = value.GetType();
+                TypeCode typeCode = Type.GetTypeCode(s);
+                if (compareOperNum == 4) keyListValueList = false;
+                return logicOper + key + compareOper + " @" + key1 + " ";
+                //return typeCode switch
+                //{
+                //    TypeCode.String => logicOper + key + compareOper + "\'" + value.ToString() + "\'",
+                //    TypeCode.Char => logicOper + key + compareOper + "\'" + value.ToString() + "\'",
+                //    TypeCode.Int32 => logicOper + key + compareOper + int.Parse(value.ToString()),
+                //    TypeCode.Double => logicOper + key + compareOper + double.Parse(value.ToString()),
+                //    //case TypeCode.Byte: return "and c." + key + "=" + (Byte)obj ;   
+                //    TypeCode.Boolean => logicOper + key + compareOper + bool.Parse(value.ToString()),
+                //    TypeCode.DateTime => logicOper + key + compareOper + (DateTime)value,
+                //    TypeCode.Int64 => logicOper + key + compareOper + long.Parse(value.ToString()),
+                //    _ => null,
+                //};
+            }
+        }
+
+        private static string ValueIsLike(string key, string key1, object value, string logicOperParams, int logicOperNum, int compareOperNum, ref bool keyListValueList)
+        {
+            string compareOperBool = " true ";
+            compareOperBool = CompareBoolSwitch(compareOperNum);
+            string logicOper = " and ";
+            if (logicOperNum != 0) logicOper = logicOperParams;
+            StringBuilder s = new StringBuilder(logicOper + " ( Contains( ");
+
+            if (value is JArray array)
+            {
+                int aa = 0;
+                foreach (JValue obja in array)
+                {
+                    if (aa != 0) s.Append("or Contains(");
+                    s.Append(key + "," + " @" + key1 + aa + " ) = " + compareOperBool + " ");
+
+                    //if (obja.Value is string a)
+                    //{
+                    //    s.Append(key + "," + "\'" + a + "\') = " + compareOperBool + " ");
+                    //}
+                    //else if (obja.Value is int b)
+                    //{
+                    //    s.Append("ToString( " + key + " )," + " \'" + b + "\' ) = " + compareOperBool + " ");
+
+                    //}
+                    //else if (obja.Value is double c)
+                    //{
+                    //    s.Append("ToString( " + key + " )," + c + "\' ) = " + compareOperBool + " ");
+                    //}
+                    //else if (obja.Value is bool d)
+                    //{
+                    //    s.Append("ToString( " + key + " )," + "\' " + d + "\' ) = " + compareOperBool + " ");
+
+                    //}
+                    //else if (obja.Value is long e)
+                    //{
+                    //    s.Append("ToString( " + key + " )," + " \'" + e + "\' ) = " + compareOperBool + " ");
+                    //}
+                    //else if (obja.Value is DateTime f)
+                    //{
+                    //    s.Append("ToString( " + key + " )," + " \'" + f + "\' ) = " + compareOperBool + " ");
+                    //}
+                    aa++;
+                }
+            }
+            else if (value is IEnumerable enumerable && !(value is String))
+            {
+                int aa = 0;
+                foreach (object obja in enumerable)
+                {
+                    if (aa != 0) s.Append("or Contains(");
+                    s.Append(key + "," + " @" + key1 + aa + " ) = " + compareOperBool + " ");
+                    aa++;
+                }
+
+            }
+            else if (value is JsonValueKind.Array && value is JsonElement jsonElement)
+            {
+                int aa = 0;
+                //jsonElement.EnumerateArray().ToArray();
+                foreach (JsonElement obja in jsonElement.EnumerateArray().ToArray())
+                {
+                    if (aa != 0) s.Append("or Contains(");
+                    s.Append(key + "," + " @" + key1 + aa + " ) = " + compareOperBool + " ");
+
+
+                    aa++;
+                }
+            }
+            else
+            {
+                Type stype = value.GetType();
+                TypeCode typeCode = Type.GetTypeCode(stype);
+                keyListValueList = false;
+                string sql = "";
+
+                sql = logicOper + "Contains( " + key + " ,  @" + key1 + " ) = " + compareOperBool + " ";
+                return sql;
+            }
+            s.Append(" )");
+            return s.ToString();
+        }
+
+        private static string CompareBoolSwitch(int compareOperNum)
+        {
+            return compareOperNum switch
+            {
+                6 => " true ",
+                7 => " false ",
+                _ => " true ",
+            };
+
+        }
+
+        private static string KeyNotElement(object value, string key, string key1, string logicOperParams, int logicOperNum, int compareOperNum)
+        {
+            string compareOperBool = " true ";
+            compareOperBool = CompareBoolSwitch(compareOperNum);
+            string logicOper = " and ";
+            int compareOper = 4;
+            if (logicOperNum != 0) logicOper = logicOperParams;
+            if (key.EndsWith(".&"))
+            {
+                key = key.Replace(".&", "");
+            }
+            else if (key.EndsWith(".|"))
+            {
+                key = key.Replace(".|", "");
+            }
+            string[] keyHead = key.Split(".");
+            CompareOperSwitch(keyHead[0], ref key, ref compareOper);
+
+            if (compareOper == 6 || compareOper == 7)
+            {
+                StringBuilder sql = new StringBuilder(logicOper + " ( Contains( ");
+                if (value is JArray jarray)
+                {
+                    int aa = 0;
+                    foreach (JValue obja in jarray)
+                    {
+                        if (aa != 0) sql.Append("or Contains(");
+                        sql.Append(" c." + key + ", @" + key1 + aa + " )= " + compareOperBool + "  ");
+
+
+                        aa++;
+                    }
+                }
+                else if (value is IEnumerable enumerable && !(value is String))
+                {
+                    int aa = 0;
+                    foreach (object obja in enumerable)
+                    {
+                        if (aa != 0) sql.Append("or Contains(");
+                        sql.Append(" c." + key + "," + " @" + key1 + aa + " ) = " + compareOperBool + "  ");
+
+                        aa++;
+                    }
+                }
+                else if (value is JsonElement jsonElement && jsonElement.ValueKind! is JsonValueKind.Array)
+                {
+                    int aa = 0;
+                    foreach (JsonElement obja in jsonElement.EnumerateArray().ToArray())
+                    {
+                        if (aa != 0) sql.Append("or Contains(");
+                        sql.Append(" c." + key + "," + " @" + key1 + aa + " ) = " + compareOperBool + "  ");
+
+                        aa++;
+                    }
+                }
+                else
+                {
+                    Type s = value.GetType();
+                    TypeCode typeCode = Type.GetTypeCode(s);
+
+                    string sql1 = "";
+                    sql1 = logicOper + "Contains(  c." + key + " ,  @" + key1 + " ) = " + compareOperBool + " ";
+
+
+                    return sql1;
+                }
+
+                sql.Append(")");
+                return sql.ToString();
+            }
+            else
+            {
+                StringBuilder sql = new StringBuilder(logicOper + " c." + key + " in (");
+                if (value is JArray array)
+                {
+                    int aa = 0;
+                    foreach (JValue obja in array)
+                    {
+
+                        sql.Append(" @" + key1 + aa + " ,");
+
+
+                        aa++;
+                    }
+                    string sqls = sql.ToString().Substring(0, sql.Length - 1);
+                    sqls += " ) ";
+                    return sqls;
+                }
+                else if (value is IEnumerable enumerable && !(value is String))
+                {
+                    int aa = 0;
+                    foreach (object obja in enumerable)
+                    {
+                        sql.Append(" @" + key1 + aa + " ,");
+
+                        aa++;
+                    }
+                    string sqls = sql.ToString().Substring(0, sql.Length - 1);
+                    sqls += " ) ";
+                    return sqls;
+                }
+                else if (value is JsonElement jsonElement)
+                {
+                    if (jsonElement.ValueKind is JsonValueKind.Array)
+                    {
+                        int aa = 0;
+                        foreach (JsonElement obja in jsonElement.EnumerateArray().ToArray())
+                        {
+                            sql.Append(" @" + key1 + aa + " ,");
+
+                            aa++;
+                        }
+                    }
+                    else
+                    {
+                        return logicOper + " c." + key + CompareOpers[compareOperNum] + " @" + key1;
+
+                    }
+
+                    string sqls = sql.ToString().Substring(0, sql.Length - 1);
+                    sqls += " ) ";
+                    return sqls;
+                }
+                else
+                {
+                    Type s = value.GetType();
+                    TypeCode typeCode = Type.GetTypeCode(s);
+
+                    return typeCode switch
+                    {
+                        TypeCode.String => logicOper + " c." + key + CompareOpers[compareOperNum] + " @" + key1,// + "\'" + value.ToString() + "\'",
+                        TypeCode.Char => logicOper + " c." + key + CompareOpers[compareOperNum] + " @" + key1,//  + "\'"  + value.ToString() + "\'",
+                        TypeCode.Int32 => logicOper + "  c." + key + CompareOpers[compareOperNum] + " @" + key1,// + int.Parse(value.ToString()),
+                        TypeCode.Double => logicOper + "  c." + key + CompareOpers[compareOperNum] + " @" + key1,// + double.Parse(value.ToString()),
+                        //case TypeCode.Byte: return "and c." + key + "=" + (Byte)obj ;   
+                        TypeCode.Boolean => logicOper + "  c." + key + CompareOpers[compareOperNum] + " @" + key1,//  + bool.Parse(value.ToString()),
+                        TypeCode.DateTime => logicOper + "  c." + key + CompareOpers[compareOperNum] + " @" + key1,//  + (DateTime)value,
+                        TypeCode.Int64 => logicOper + "  c." + key + CompareOpers[compareOperNum] + " @" + key1,// + long.Parse(value.ToString()),
+                        _ => null,
+                    };
+                }
+            }
+        }
+
+
+        public enum LogicOper : int
+        {
+            and = 0, or = 1
+        }
+        public enum CompareOper : int
+        {
+            moreThan = 0, lessThan = 1, notMoreThan = 2, notLessThan = 3, equal = 4, notEqual = 5, like = 6, notLike = 7, IN = 8
+        }
+
+
+
+
+        private static Dictionary<string, object> GetParmeter(Dictionary<string, object> dict, Dictionary<string, object> parmeters)
+        {
+            foreach (KeyValuePair<string, object> keyValue in dict)
+            {
+                string key = "";
+                string[] keyHead = keyValue.Key.Split(".");
+                switch (keyHead[0])
+                {
+                    case ">":
+                        key = keyValue.Key.Replace(">.", "");
+                        break;
+                    case "<":
+                        key = keyValue.Key.Replace("<.", "");
+                        break;
+                    case "<=":
+                        key = keyValue.Key.Replace("<=.", "");
+                        break;
+                    case ">=":
+                        key = keyValue.Key.Replace(">=.", "");
+                        break;
+                    case "=":
+                        key = keyValue.Key.Replace("=.", "");
+                        break;
+                    case "!=":
+                        key = keyValue.Key.Replace("!=.", "");
+                        break;
+                    case "$":
+                        key = keyValue.Key.Replace("$.", "");
+                        break;
+                    case "!$":
+                        key = keyValue.Key.Replace("!$.", "");
+                        break;
+                    default:
+                        key = keyValue.Key;
+                        break;
+                }
+                if (key.EndsWith(".&"))
+                {
+                    key = key.Replace(".&", "");
+                }
+                else if (key.EndsWith(".|"))
+                {
+                    key = key.Replace(".|", "");
+                }
+                key = key.Replace("[*].", "");
+                key = key.Replace(".", "");
+                if (keyValue.Value is JArray array)
+                {
+                    int aa = 0;
+                    foreach (JValue obja in array)
+                    {
+                        parmeters.Add("@" + key + aa, obja);
+                        aa++;
+                    }
+                }
+                else if (keyValue.Value is JsonElement jsonElement)
+                {
+                    if (jsonElement.ValueKind is JsonValueKind.Array)
+                    {
+                        int aa = 0;
+                        foreach (JsonElement obja in jsonElement.EnumerateArray().ToArray())
+                        {
+                            if (obja.ValueKind is JsonValueKind.String)
+                            {
+                                parmeters.Add("@" + key + aa, obja.ToString());
+                            }
+                            if (obja.ValueKind is JsonValueKind.Number)
+                            {
+                                parmeters.Add("@" + key + aa, double.Parse(obja.ToString()));
+                            }
+                            if (obja.ValueKind is JsonValueKind.True)
+                            {
+                                parmeters.Add("@" + key + aa, bool.Parse(obja.ToString()));
+                            }
+                            if (obja.ValueKind is JsonValueKind.False)
+                            {
+                                parmeters.Add("@" + key + aa, bool.Parse(obja.ToString()));
+                            }
+                            aa++;
+                        }
+                    }
+                    else
+                    {
+                        if (jsonElement.ValueKind is JsonValueKind.String)
+                        {
+                            parmeters.Add("@" + key, keyValue.Value.ToString());
+                        }
+                        else if (jsonElement.ValueKind is JsonValueKind.Number)
+                        {
+                            parmeters.Add("@" + key, double.Parse(keyValue.Value.ToString()));
+                        }
+                        else if (jsonElement.ValueKind is JsonValueKind.True)
+                        {
+                            parmeters.Add("@" + key, bool.Parse(keyValue.Value.ToString()));
+                        }
+                        else if (jsonElement.ValueKind is JsonValueKind.False)
+                        {
+                            parmeters.Add("@" + key, bool.Parse(keyValue.Value.ToString()));
+                        }
+                        else
+                        {
+                            parmeters.Add("@" + key, keyValue.Value.ToString());
+                        }
+                    }
+                }
+                else if (keyValue.Value is IEnumerable enumerable)
+                {
+                    int aa = 0;
+                    foreach (object obja in enumerable)
+                    {
+                        parmeters.Add("@" + key + aa, obja);
+                        aa++;
+                    }
+                }
+                else
+                {
+                    parmeters.Add("@" + key, keyValue.Value);
+                }
+                //parmeters.Add("@" + key, keyValue.Value.ToString());
+            }
+            return parmeters;
+        }
+
+
+    }
+}

+ 45 - 0
TEAMModelOS.SDK/Module/AzureCosmosDBV3/SystemTextJsonCosmosSerializer.cs

@@ -0,0 +1,45 @@
+using Microsoft.Azure.Cosmos;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
+{
+    internal sealed class SystemTextJsonCosmosSerializer : CosmosSerializer
+    {
+        private readonly JsonSerializerOptions _options;
+
+        internal SystemTextJsonCosmosSerializer(JsonSerializerOptions options)
+        {
+            _options = options;
+        }
+
+        /// <inheritdoc />
+        public override T FromStream<T>(Stream stream)
+        {
+            // Have to dispose of the stream, otherwise the Cosmos SDK throws.
+            // https://github.com/Azure/azure-cosmos-dotnet-v3/blob/0843cae3c252dd49aa8e392623d7eaaed7eb712b/Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonSerializerWrapper.cs#L22
+            // https://github.com/Azure/azure-cosmos-dotnet-v3/blob/0843cae3c252dd49aa8e392623d7eaaed7eb712b/Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonDotNetSerializer.cs#L73
+            using (stream)
+            {
+                // TODO Would be more efficient if CosmosSerializer supported async
+                // See https://github.com/Azure/azure-cosmos-dotnet-v3/issues/715
+                using var memory = new MemoryStream((int)stream.Length);
+                stream.CopyTo(memory);
+
+                byte[] utf8Json = memory.ToArray();
+                return JsonSerializer.Deserialize<T>(utf8Json, _options);
+            }
+        }
+
+        /// <inheritdoc />
+        public override Stream ToStream<T>(T input)
+        {
+            byte[] utf8Json = JsonSerializer.SerializeToUtf8Bytes(input, _options);
+            return new MemoryStream(utf8Json);
+        }
+    }
+}

+ 1 - 0
TEAMModelOS.SDK/TEAMModelOS.SDK.csproj

@@ -29,6 +29,7 @@
     <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.6.0" />
     <PackageReference Include="WindowsAzure.Storage" Version="9.3.3" />
     <PackageReference Include="XC.Framework.Security.RSAUtil" Version="1.0.1" />
+    <PackageReference Include="Microsoft.Azure.Cosmos" Version="3.6.0" />
     <PackageReference Include="Microsoft.Azure.Cosmos.Table" Version="2.0.0-preview" />
   </ItemGroup>
 </Project>