/// <summary>
        /// Returns a single entity by a single id from table "Ts".
        /// Id must be marked with [Key] attribute.
        /// Entities created from interfaces are tracked/intercepted for changes and used by the Update() extension
        /// for optimal performance.
        /// </summary>
        /// <typeparam name="T">Interface or type to create and populate</typeparam>
        /// <param name="connection">Open SqlConnection</param>
        /// <param name="isasc">isasc</param>
        /// <param name="entity">entity</param>
        /// <param name="pageIndex">pageIndex,from start 1</param>
        /// <param name="pageSize">pageSize</param>
        /// <param name="transaction">The transaction to run under, null (the default) if none</param>
        /// <param name="commandTimeout">Number of seconds before command execution timeout</param>
        /// <returns>Entity of T</returns>
        public static async Task <IEnumerable <T> > GetPageAsync <T>(this IDbConnection connection, int pageIndex, int pageSize, object entity = null, bool isasc = true, IDbTransaction transaction = null, int?commandTimeout = null) where T : class
        {
            var type = typeof(T);

            if (!GetListQueries.TryGetValue(type.TypeHandle, out string sql))
            {
                var name = GetTableName(type);

                sql = $"select * from {name}";
                GetListQueries[type.TypeHandle] = sql;
            }
            var           param = GetParameters(entity);
            StringBuilder sb    = new StringBuilder();

            sb.Append(sql);
            var adapter = GetFormatter(connection);

            if (param != null && param.ParameterNames.Count() > 0)
            {
                sb.Append(" where ");
                int length = param.ParameterNames.Count();
                int index  = 1;
                foreach (var item in param.ParameterNames)
                {
                    adapter.AppendColumnNameEqualsValue(sb, item);
                    if (index < length)
                    {
                        sb.Append(" and ");
                    }
                    index++;
                }
            }
            AppendAsc(sb, type, isasc);
            adapter.AppendPageInfo(sb, pageIndex, pageSize);
            if (!type.IsInterface())
            {
                return(await connection.QueryAsync <T>(sb.ToString(), param, transaction, commandTimeout : commandTimeout));
            }
            var result = await connection.QueryAsync(sb.ToString(), param, transaction, commandTimeout : commandTimeout);

            var list = new List <T>();

            foreach (IDictionary <string, object> res in result)
            {
                var obj = ProxyGenerator.GetInterfaceProxy <T>();
                foreach (var property in TypePropertiesCache(type))
                {
                    var val = res[property.Name];
                    property.SetValue(obj, Convert.ChangeType(val, property.PropertyType), null);
                }
                ((IProxy)obj).IsDirty = false;
                list.Add(obj);
            }
            return(list);
        }
        /// <summary>
        /// Returns a single entity by a single id from table "Ts".
        /// Id must be marked with [Key] attribute.
        /// Entities created from interfaces are tracked/intercepted for changes and used by the Update() extension
        /// for optimal performance.
        /// </summary>
        /// <typeparam name="T">Interface or type to create and populate</typeparam>
        /// <param name="connection">Open SqlConnection</param>
        /// <param name="entity"></param>
        /// <param name="transaction">The transaction to run under, null (the default) if none</param>
        /// <param name="commandTimeout">Number of seconds before command execution timeout</param>
        /// <returns>Entity of T</returns>
        public static async Task <T> GetSigleAsync <T>(this IDbConnection connection, object entity = null, IDbTransaction transaction = null, int?commandTimeout = null) where T : class
        {
            var           type = typeof(T);
            string        sql  = "";
            var           name = GetTableName(type);
            StringBuilder sb   = new StringBuilder();

            if (entity == null)
            {
                if (!GetListQueries.TryGetValue(type.TypeHandle, out sql))
                {
                    sb.Append($"select * from {name}");
                    sql = sb.ToString();
                    GetListQueries[type.TypeHandle] = sql;
                }
                else
                {
                    sb.Append(sql);
                }
            }
            else
            {
                var entityType = entity.GetType();
                if (!GetListQueries.TryGetValue(entityType.TypeHandle, out sql))
                {
                    sb.Append($"select * from {name}");
                    var param = GetParameters(entity);
                    if (param != null && param.ParameterNames.Count() > 0)
                    {
                        sb.Append(" where ");
                        var adapter = GetFormatter(connection);
                        int length  = param.ParameterNames.Count();
                        int index   = 1;
                        foreach (var item in param.ParameterNames)
                        {
                            adapter.AppendColumnNameEqualsValue(sb, item);
                            if (index < length)
                            {
                                sb.Append(" and ");
                            }
                            index++;
                        }
                    }
                    GetListQueries[type.TypeHandle] = sb.ToString();
                }
                else
                {
                    sb.Append(sql);
                }
            }
            sql = sb.ToString();
            if (!type.IsInterface())
            {
                return(await connection.QueryFirstOrDefaultAsync <T>(sql, entity, transaction, commandTimeout : commandTimeout));
            }

            var res = (await connection.QueryFirstOrDefaultAsync <dynamic>(sql, entity).ConfigureAwait(false)).FirstOrDefault() as IDictionary <string, object>;

            if (res == null)
            {
                return(null);
            }

            var obj = ProxyGenerator.GetInterfaceProxy <T>();

            foreach (var property in TypePropertiesCache(type))
            {
                var val = res[property.Name];
                property.SetValue(obj, Convert.ChangeType(val, property.PropertyType), null);
            }

            ((IProxy)obj).IsDirty = false;   //reset change tracking and return

            return(obj);
        }