using System;
using System.Configuration;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Dapper;
using DapperORM.Common.Models;
using DapperORM.Common.Enums;
using DapperORM.Common.Extention.DTO;
using System.Data.Common;

namespace DapperORM.ORMExtention
{
    /// <summary>
    /// 数据库连接对象扩展
    /// </summary>
    internal static class ConnectionExtention
    {
        /// <summary>
        /// 内部补充转义字符前缀，防止和数据库关键字名称冲突，如 `name`
        /// </summary>
        private static readonly string _ColPrefix = ConfigurationManager.AppSettings["ColPrefix"] ?? string.Empty;

        /// <summary>
        /// 内部补充转义字符后缀，防止和数据库关键字名称冲突，如 `name`
        /// </summary>
        private static readonly string _ColPostfix = ConfigurationManager.AppSettings["ColPostfix"] ?? string.Empty;

        #region 插入扩展

        /// <summary>
        /// 插入新记录
        /// </summary>
        /// <typeparam name="T">数据库表实体类型</typeparam>
        /// <param name="conn">数据库连接</param>
        /// <param name="model">对应实体</param>
        /// <param name="tableName">如果为空则以T.GetType().Name</param>
        /// <returns></returns>
        public static async Task<ResultModel> InsertAsync<T>(this IDbConnection conn, T model, string tableName = null)
        {
            if (string.IsNullOrEmpty(tableName))
                tableName = model.GetType().Name;

            bool isIdAuto = false;

            List<PropertyInfo> prolist = new List<PropertyInfo>();
            string sql = GetInsertSql<T>(tableName, ref isIdAuto, out prolist);

            long count = await conn.ExecuteAsync(sql, model);

            return count > 0 ? new ResultModel(ResultType.Success) : new ResultModel(ResultType.AddFail, "添加操作失败！");
        }

        /// <summary>
        /// 单表批量插入
        /// </summary>
        /// <typeparam name="T">数据库表实体类型</typeparam>
        /// <param name="conn">数据库连接</param>
        /// <param name="list">对应实体集合</param>
        /// <param name="tableName">如果为空则以T.GetType().Name</param>
        /// <returns></returns>
        public static async Task<ResultModel> InsertManyAsync<T>(this IDbConnection conn, IList<T> list, string tableName = null)
        {
            if (string.IsNullOrEmpty(tableName))
                tableName = list.FirstOrDefault().GetType().Name;

            bool isIdAuto = false;

            List<PropertyInfo> prolist = new List<PropertyInfo>();
            string sql = GetInsertSql<T>(tableName, ref isIdAuto, out prolist);

            long count = await conn.ExecuteAsync(sql, list);

            return count > 0 ? new ResultModel(ResultType.Success) : new ResultModel(ResultType.AddFail, "添加操作失败！");
        }

        /// <summary>
        /// 获得插入语句
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="tableName">表明</param>
        /// <param name="haveAuto">是否有自增</param>
        /// <param name="proList">对象属性</param>
        /// <returns></returns>
        private static string GetInsertSql<T>(string tableName, ref bool haveAuto, out List<PropertyInfo> proList)
        {
            //  1.  生成语句
            var sqlCols = new StringBuilder("INSERT INTO ");
            sqlCols.Append(tableName).Append(" (");

            var sqlValues = new StringBuilder(" VALUES (");
            var properties = typeof(T).GetProperties();
            proList = new List<PropertyInfo>(properties.Length);

            var isStart = false;
            foreach (var propertyInfo in properties)
            {
                var isAutoAttr = propertyInfo.GetCustomAttribute<AutoColumnAttribute>();
                var isIgnoreAttr = propertyInfo.GetCustomAttribute<IgnoreColumnAttribute>();

                if (isAutoAttr != null && isAutoAttr.IsAuto)
                {
                    haveAuto = true;
                    continue;
                }
                else if (isIgnoreAttr != null && isIgnoreAttr.IsIgnore)
                {
                    continue;
                }
                if (isStart)
                {
                    sqlCols.Append(",");
                    sqlValues.Append(",");
                }
                else
                    isStart = true;

                sqlCols.Append(_ColPrefix).Append(propertyInfo.Name).Append(_ColPostfix);
                sqlValues.Append("@").Append(propertyInfo.Name);
                proList.Add(propertyInfo);
            }
            sqlCols.Append(")");
            sqlValues.Append(")");
            sqlCols.Append(sqlValues);

            if (haveAuto)
                sqlCols.Append(";SELECT LAST_INSERT_ID();");
            else
                sqlCols.Append(";");
            return sqlCols.ToString();
        }

        /// <summary>
        /// 获得插入语句
        /// </summary>
        /// <typeparam name="T">数据库表实体类型</typeparam>
        /// <returns></returns>
        internal static string GetInsertSql<T>()
        {
            string tableName = typeof(T).Name;
            //  1.  生成语句
            var sqlCols = new StringBuilder("INSERT INTO ");
            sqlCols.Append(tableName).Append(" (");

            var sqlValues = new StringBuilder(" VALUES (");
            var properties = typeof(T).GetProperties();

            var isStart = false;
            foreach (var propertyInfo in properties)
            {
                var isAutoAttr = propertyInfo.GetCustomAttribute<AutoColumnAttribute>();
                var isIgnoreAttr = propertyInfo.GetCustomAttribute<IgnoreColumnAttribute>();

                if (isAutoAttr != null && isAutoAttr.IsAuto)
                {
                    continue;
                }
                else if (isIgnoreAttr != null && isIgnoreAttr.IsIgnore)
                {
                    continue;
                }
                if (isStart)
                {
                    sqlCols.Append(",");
                    sqlValues.Append(",");
                }
                else
                    isStart = true;

                sqlCols.Append(_ColPrefix).Append(propertyInfo.Name).Append(_ColPostfix);
                sqlValues.Append("@").Append(propertyInfo.Name);
            }
            sqlCols.Append(")");
            sqlValues.Append(")");
            sqlCols.Append(sqlValues);
            sqlCols.Append(";");
            return sqlCols.ToString();
        }

        #endregion

        #region 删除扩展

        /// <summary>
        /// 物理删除
        /// </summary>
        /// <typeparam name="T">要删除的数据库表实体类型</typeparam>
        /// <param name="conn">数据库连接</param>
        /// <param name="where">删除条件</param>
        /// <param name="tableName">表名称</param>
        /// <returns></returns>
        public static async Task<ResultModel> DeleteAsync<T>(this IDbConnection conn, Expression<Func<T, bool>> where, string tableName = null)
        {
            if (string.IsNullOrEmpty(tableName))
                tableName = typeof(T).Name;

            StringBuilder sqlBuilder = new StringBuilder();
            SqlExpressionVisitor visitor = new SqlExpressionVisitor();
            GetDeleteSql(tableName, where, visitor, sqlBuilder);
            return await ExecuteDeleteAsync<T>(conn, tableName, sqlBuilder, visitor);
        }

        /// <summary>
        /// 获取删除语句
        /// </summary>
        /// <typeparam name="T">要删除的数据库表实体类型</typeparam>
        /// <param name="tableName">表名称</param>
        /// <param name="where">where条件</param>
        /// <param name="visitor">sql表达式访问器</param>
        /// <param name="sql">sql语句</param>
        private static void GetDeleteSql<T>(string tableName, Expression<Func<T, bool>> where, SqlExpressionVisitor visitor, StringBuilder sql)
        {
            sql.Append("DELETE FROM ").Append(tableName);

            sql.Append(" ").Append(VisitWhereExpress(visitor, where));
        }

        /// <summary>
        /// 获取删除语句
        /// </summary>
        /// <typeparam name="T">要删除的数据库表实体类型</typeparam>
        /// <param name="where">where条件</param>
        /// <returns></returns>
        internal static string GetDeleteSql<T>(Expression<Func<T, bool>> where)
        {
            string tableName = typeof(T).Name;
            StringBuilder sql = new StringBuilder();
            SqlExpressionVisitor visitor = new SqlExpressionVisitor();
            sql.Append("DELETE FROM ").Append(tableName);
            sql.Append(" ").Append(VisitWhereExpress(visitor, where));
            return sql.ToString();
        }

        /// <summary>
        /// 执行删除
        /// </summary>
        /// <typeparam name="T">要删除的数据库表实体类型</typeparam>
        /// <param name="conn">数据库连接</param>
        /// <param name="tableName"></param>
        /// <param name="sqlBuilder"></param>
        /// <param name="visitor"></param>
        /// <returns></returns>
        private static async Task<ResultModel> ExecuteDeleteAsync<T>(IDbConnection conn, string tableName,
            StringBuilder sqlBuilder,
            SqlExpressionVisitor visitor)
        {
            OrmOperateInfo opeInfo = GetOrmOperateCache<T>(conn.ConnectionString, sqlBuilder.ToString(), tableName,
                visitor.Properties.Select(e => e.Value));

            Dictionary<string, object> paraDics = new Dictionary<string, object>();
            foreach (var p in visitor.Parameters)
                paraDics.Add(p.Key, p.Value);

            var row = await conn.ExecuteAsync(opeInfo.Sql, new DynamicParameters(paraDics));
            return row > 0 ? new ResultModel(ResultType.Success) : new ResultModel(ResultType.DeleteFail, "删除失败");
        }

        #endregion

        #region 更新扩展

        #region 更新全部字段
        /// <summary>
        /// 更新全部字段
        /// </summary>
        /// <typeparam name="T">更新的实体类型</typeparam>
        /// <param name="model">需要更新的实体</param>
        /// <param name="where">更新条件，为空则默认使用Id</param>
        /// <param name="tableName">表名称，如果为空则以T.GetType().Name</param>
        /// <returns></returns>
        public static async Task<ResultModel> UpdateAllAsync<T>(this IDbConnection conn, T model,
            Expression<Func<T, bool>> where = null, string tableName = null)
        {
            if (string.IsNullOrEmpty(tableName))
                tableName = typeof(T).Name;

            SqlExpressionVisitor visitor = new SqlExpressionVisitor();
            StringBuilder sqlStr = new StringBuilder("UPDATE ");

            string whereSql = VisitWhereExpress(visitor, where); //  放在前面获取where后的成员参数，update时排除
            GetUpdateAllSql<T>(tableName, sqlStr, visitor);
            sqlStr.Append(whereSql); //  where语句追加在后边

            return await ExecuteUpdateAsync(conn, model, tableName, sqlStr, visitor);
        }

        /// <summary>
        /// 获取更新全部字段语句
        /// </summary>
        /// <typeparam name="T">更新的实体类型</typeparam>
        /// <param name="tableName">表名称，如果为空则以T.GetType().Name</param>
        /// <param name="sqlStr"></param>
        /// <param name="visitor"></param>
        private static void GetUpdateAllSql<T>(string tableName, StringBuilder sqlStr, SqlExpressionVisitor visitor)
        {
            sqlStr.Append(tableName).Append(" SET ");
            var pros = typeof(T).GetProperties();

            var isStart = false;
            foreach (var pro in pros)
            {
                var isAutoAttr = pro.GetCustomAttribute<AutoColumnAttribute>();
                var isIgnoreAttr = pro.GetCustomAttribute<IgnoreColumnAttribute>();
                if (visitor.Properties.ContainsKey(pro.Name)
                    || isAutoAttr != null && isAutoAttr.IsAuto)
                    continue;
                else if (isIgnoreAttr != null && isIgnoreAttr.IsIgnore)
                    continue;

                sqlStr.Append(isStart ? "," : string.Empty)
                    .Append(_ColPrefix).Append(pro.Name).Append(_ColPostfix).Append("=").Append("@").Append(pro.Name);

                if (!isStart)
                    isStart = true;

                visitor.Properties.Add(pro.Name, pro);
            }
        }
        #endregion

        #region 更新部分字段
        /// <summary>
        /// 更新部分字段
        /// </summary>
        /// <typeparam name="T">要更新的实体类型</typeparam>
        /// <param name="conn">数据库连接</param>
        /// <param name="model">实体对象</param>
        /// <param name="update">表达式,要更新的属性</param>
        /// <param name="tableName">表名称</param>
        /// <param name="where">表达式，where语句</param>
        /// <returns></returns>
        public static async Task<ResultModel> UpdatePartailAsync<T>(this IDbConnection conn, T model,
            Expression<Func<T, object>> update, Expression<Func<T, bool>> where = null, string tableName = null)
        {
            if (string.IsNullOrEmpty(tableName))
                tableName = typeof(T).Name;

            StringBuilder sqlBuilder = new StringBuilder();
            SqlExpressionVisitor visitor = new SqlExpressionVisitor();
            GetUpdateExpressionSql(update, where, tableName, visitor, sqlBuilder);

            return await ExecuteUpdateAsync(conn, model, tableName, sqlBuilder, visitor);
        }

        /// <summary>
        /// 获取更新表达式的SQL语句
        /// </summary>
        /// <typeparam name="T">要更新的实体类型</typeparam>
        /// <param name="update">要更新的字段表达式</param>
        /// <param name="where">条件表达式</param>
        /// <param name="tableName">表名称</param>
        /// <param name="visitor">表达式访问器</param>
        /// <param name="sql">sql</param>
        private static void GetUpdateExpressionSql<T>(Expression<Func<T, object>> update,
            Expression<Func<T, bool>> where, string tableName,
            SqlExpressionVisitor visitor, StringBuilder sql)
        {
            sql.Append("UPDATE ").Append(tableName).Append(" SET ");

            SqlVistorFlag updateFlag = new SqlVistorFlag(SqlVistorType.Update);
            visitor.Visit(update, updateFlag);

            sql.Append(updateFlag.Sql);
            sql.Append(" ").Append(VisitWhereExpress(visitor, where));
        }
        #endregion

        #region 执行更新
        /// <summary>
        /// 执行更新
        /// </summary>
        /// <typeparam name="T">要更新的实体类型</typeparam>
        /// <param name="conn">数据库连接</param>
        /// <param name="model">实体对象</param>
        /// <param name="tableName">表名称</param>
        /// <param name="sqlBuilder">sql</param>
        /// <param name="visitor">表达式访问器</param>
        /// <returns></returns>
        private static async Task<ResultModel> ExecuteUpdateAsync<T>(IDbConnection conn, T model, string tableName,
            StringBuilder sqlBuilder,
            SqlExpressionVisitor visitor)
        {
            OrmOperateInfo opeInfo = GetOrmOperateCache<T>(conn.ConnectionString, sqlBuilder.ToString(), tableName,
                visitor.Properties.Select(e => e.Value));
            Dictionary<string, object> paraDics = opeInfo.ParaFunc?.Invoke(model) ?? new Dictionary<string, object>();

            foreach (var p in visitor.Parameters)
                paraDics.Add(p.Key, p.Value);

            var row = await conn.ExecuteAsync(opeInfo.Sql, new DynamicParameters(paraDics));
            return row > 0 ? new ResultModel(ResultType.Success) : new ResultModel(ResultType.UpdateFail, "更新失败");
        }
        #endregion

        /// <summary>
        /// 获取更新语句
        /// </summary>
        /// <typeparam name="T">要更新的实体类型</typeparam>
        /// <param name="update">要更新的字段，空更新全部字段</param>
        /// <param name="where">where条件</param>
        /// <returns></returns>
        internal static string GetUpdateSql<T>(Expression<Func<T, object>> update, Expression<Func<T, bool>> where = null)
        {
            string tableName = typeof(T).Name;
            StringBuilder sql = new StringBuilder();
            SqlExpressionVisitor visitor = new SqlExpressionVisitor();
            sql.Append("UPDATE ").Append(tableName).Append(" SET ");
            string whereSql = VisitWhereExpress(visitor, where);
            if (update != null)
            {
                SqlVistorFlag updateFlag = new SqlVistorFlag(SqlVistorType.Update);
                visitor.Visit(update, updateFlag);
                sql.Append(updateFlag.Sql);
            }
            else
            {
                var pros = typeof(T).GetProperties();

                var isStart = false;
                foreach (var pro in pros)
                {
                    var isAutoAttr = pro.GetCustomAttribute<AutoColumnAttribute>();
                    var isIgnoreAttr = pro.GetCustomAttribute<IgnoreColumnAttribute>();
                    if (visitor.Properties.ContainsKey(pro.Name)
                        || isAutoAttr != null && isAutoAttr.IsAuto)
                        continue;
                    else if (isIgnoreAttr != null && isIgnoreAttr.IsIgnore)
                        continue;

                    sql.Append(isStart ? "," : string.Empty)
                        .Append(_ColPrefix).Append(pro.Name).Append(_ColPostfix).Append("=").Append("@").Append(pro.Name);

                    if (!isStart)
                        isStart = true;

                    visitor.Properties.Add(pro.Name, pro);
                }
            }
            sql.Append(" ").Append(whereSql);
            return sql.ToString();
        }

        #region 处理where条件表达式
        /// <summary>
        ///   处理where条件表达式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="visitor"></param>
        /// <param name="where"></param>
        private static string VisitWhereExpress<T>(SqlExpressionVisitor visitor, Expression<Func<T, bool>> where)
        {
            if (where != null)
            {
                SqlVistorFlag whereFlag = new SqlVistorFlag(SqlVistorType.Where);
                visitor.Visit(@where, whereFlag);
                return string.Concat(" WHERE ", whereFlag.Sql);
            }
            else
                return string.Empty;
        }
        #endregion

        #endregion

        #region 查询单个对象扩展
        /// <summary>
        ///  获取单项扩展
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="conn">数据库连接</param>
        /// <param name="model"></param>
        /// <param name="whereExp">条件</param>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        public static async Task<T> GetAsync<T>(this IDbConnection conn, Expression<Func<T, bool>> whereExp = null, Expression<Func<T, object>> selectExp = null, IDictionary<string, bool> sort = null, string tableName = null)
        {
            if (string.IsNullOrEmpty(tableName))
                tableName = typeof(T).Name;

            SqlExpressionVisitor sqlVisitor = new SqlExpressionVisitor();
            string whereSql = VisitWhereExpress(sqlVisitor, whereExp);

            string sqlStr = string.Empty;
            if (selectExp == null)
                sqlStr = string.Concat("SELECT * FROM ", tableName, whereSql);
            else
            {
                SqlVistorFlag selectFlag = new SqlVistorFlag(SqlVistorType.Select);
                sqlVisitor.Visit(selectExp, selectFlag);
                sqlStr = string.Concat("SELECT ", selectFlag.Sql, " FROM ", tableName, whereSql);
            }
            OrmOperateInfo opeInfo = GetOrmOperateCache<T>(conn.ConnectionString, sqlStr, tableName, sqlVisitor.Properties.Select(e => e.Value));
            Dictionary<string, object> paraDics = new Dictionary<string, object>();

            foreach (var p in sqlVisitor.Parameters)
                paraDics.Add(p.Key, p.Value);

            return await conn.QueryFirstOrDefaultAsync<T>(opeInfo.Sql, paraDics);
        }
        #endregion

        #region 查询集合扩展
        /// <summary>
        /// 查询集合扩展
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="conn">数据库连接</param>
        /// <param name="whereExp">条件</param>
        /// <param name="model"></param>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        public static async Task<IEnumerable<T>> FetchAsync<T>(this IDbConnection conn, Expression<Func<T, bool>> whereExp = null, Expression<Func<T, object>> selectExp = null, IDictionary<string, bool> sort = null, string tableName = null)
        {
            if (string.IsNullOrEmpty(tableName))
                tableName = typeof(T).Name;

            SqlExpressionVisitor sqlVisitor = new SqlExpressionVisitor();
            string whereSql = VisitWhereExpress(sqlVisitor, whereExp);
            string sqlStr = string.Empty;
            if (selectExp == null)
                sqlStr = string.Concat("SELECT * FROM ", tableName, whereSql);
            else
            {
                SqlVistorFlag selectFlag = new SqlVistorFlag(SqlVistorType.Select);
                sqlVisitor.Visit(selectExp, selectFlag);
                sqlStr = string.Concat("SELECT ", selectFlag.Sql, " FROM ", tableName, whereSql);
            }

            if (sort != null)
                sqlStr = string.Concat(sqlStr, GetSortStr(sort));

            OrmOperateInfo opeInfo = GetOrmOperateCache<T>(conn.ConnectionString, sqlStr, tableName, sqlVisitor.Properties.Select(e => e.Value));
            Dictionary<string, object> paraDics = new Dictionary<string, object>();

            foreach (var p in sqlVisitor.Parameters)
                paraDics.Add(p.Key, p.Value);

            return await conn.QueryAsync<T>(opeInfo.Sql, paraDics);
        }
        #endregion

        #region 查询记录条数扩展
        /// <summary>
        /// 查询记录条数扩展
        /// </summary>
        /// <param name="conn">数据库连接</param>
        /// <param name="whereExp">查询条件</param>
        /// <param name="tableName">表名称</param>
        /// <returns></returns>
        public static async Task<int> GetCountAsync<T>(this IDbConnection conn, Expression<Func<T, bool>> whereExp = null, string tableName = null)
        {
            if (string.IsNullOrEmpty(tableName))
                tableName = typeof(T).Name;

            SqlExpressionVisitor sqlVisitor = new SqlExpressionVisitor();
            string whereSql = VisitWhereExpress(sqlVisitor, whereExp);

            string sqlStr = string.Concat("SELECT COUNT(1) FROM ", tableName, whereSql);

            OrmOperateInfo opeInfo = GetOrmOperateCache<T>(conn.ConnectionString, sqlStr, tableName, sqlVisitor.Properties.Select(e => e.Value));
            Dictionary<string, object> paraDics = new Dictionary<string, object>();

            foreach (var p in sqlVisitor.Parameters)
                paraDics.Add(p.Key, p.Value);

            return await conn.ExecuteScalarAsync<int>(opeInfo.Sql, paraDics);
        }
        #endregion

        #region 查询返回dataset扩展

        /// <summary>
        /// 查询返回dataset扩展
        /// </summary>
        /// <param name="conn">数据库连接</param>
        /// <param name="adapter">适配器</param>
        /// <param name="sql">执行语句</param>
        /// <param name="param">参数</param>
        /// <param name="commandTimeout">超时时间</param>
        /// <param name="commandType">命令类型</param>
        /// <returns></returns>
        public static async Task<DataSet> QueryDataSetAsync(this IDbConnection conn, string sql, Dictionary<string, object> param, int? commandTimeout = null, CommandType? commandType = null)
        {
            try
            {
                var command = conn.CreateCommand();
                command.Connection = conn;
                command.CommandText = sql;
                command.CommandTimeout = commandTimeout ?? 30;
                command.CommandType = commandType ?? CommandType.Text;

                if (param != null)
                {
                    foreach (var item in param)
                    {
                        var dbParam = command.CreateParameter();
                        dbParam.Direction = ParameterDirection.Input;
                        dbParam.ParameterName = item.Key;
                        dbParam.Value = item.Value ?? DBNull.Value;
                        dbParam.DbType = GetDbType(item.Value);
                        command.Parameters.Add(dbParam);
                    }
                }
                using (var reader = await GetDbReaderAsync((DbCommand)command).ConfigureAwait(false))
                {
                    return reader.ToDataSet();
                }
            }
            finally
            {
                conn.Close();
                conn.Dispose();
            }
        }

        /// <summary>
        /// 执行datareader
        /// </summary>
        /// <param name="cmd">命令</param>
        /// <param name="commandBehavior">行为</param>
        /// <returns></returns>
        private static Task<DbDataReader> GetDbReaderAsync(DbCommand cmd, CommandBehavior? commandBehavior = null)
        {
            var task = cmd.ExecuteReaderAsync(commandBehavior.GetValueOrDefault(), System.Threading.CancellationToken.None);
            return task;
        }

        /// <summary>
        /// DbDataReader转DataSet
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        private static DataSet ToDataSet(this DbDataReader reader)
        {
            DataSet ds = new DataSet();
            do
            {
                DataTable schemaTable = reader.GetSchemaTable();
                DataTable dataTable = new DataTable();
                if (schemaTable != null)
                {
                    for (int i = 0; i < schemaTable.Rows.Count; i++)
                    {
                        DataRow dataRow = schemaTable.Rows[i];
                        string columnName = (string)dataRow["ColumnName"];
                        DataColumn column = new DataColumn(columnName, (Type)dataRow["DataType"]);
                        dataTable.Columns.Add(column);
                    }
                    ds.Tables.Add(dataTable);
                    while (reader.Read())
                    {
                        DataRow newRow = dataTable.NewRow();
                        for (int i = 0; i < reader.FieldCount; i++)
                        {
                            newRow[i] = reader.GetValue(i);
                        }
                        dataTable.Rows.Add(newRow);
                    }
                }
                else
                {
                    return null;
                }
            }

            while (reader.NextResult());

            return ds;
        }

        #endregion

        #region 执行非查询语句
        /// <summary>
        /// 执行非查询语句
        /// </summary>
        /// <param name="conn">数据库连接</param>
        /// <param name="sql">执行语句</param>
        /// <param name="param">参数</param>
        /// <param name="trans">事务</param>
        /// <param name="commandTimeout">超时时间</param>
        /// <param name="commandType">类型</param>
        /// <returns></returns>
        public static async Task<ResultModel> ExecuteNonQueryAsync(this IDbConnection conn, string sql, Dictionary<string, object> param, IDbTransaction trans = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            long count = await conn.ExecuteAsync(sql, param, trans, commandTimeout, commandType);

            return count > 0 ? new ResultModel(ResultType.Success) : new ResultModel(ResultType.Failure, "操作失败！");
        }
        #endregion

        #region 获得排序
        /// <summary>
        /// 获得排序
        /// </summary>
        /// <param name="sort"></param>
        /// <returns></returns>
        private static string GetSortStr(IDictionary<string, bool> sort)
        {
            if (sort == null || sort.Count == 0)
                return string.Empty;
            else
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(" ORDER BY ");
                foreach (var item in sort)
                {
                    sb.Append(item.Key).Append(item.Value ? " ASC " : " DESC ").Append(" , ");
                }
                string sortStr = sb.ToString();
                return sortStr.Remove(sortStr.LastIndexOf(","), 1);
            }
        }
        #endregion

        #region 操作信息
        /// <summary>
        /// 操作信息
        /// </summary>
        /// <typeparam name="T">操作的实体类型</typeparam>
        /// <param name="conStr">连接字符</param>
        /// <param name="sql">执行的语句</param>
        /// <param name="tableName">表名称</param>
        /// <param name="prolist">属性集合</param>
        /// <returns></returns>
        private static OrmOperateInfo GetOrmOperateCache<T>(string conStr, string sql, string tableName,
            IEnumerable<PropertyInfo> prolist)
        {
            if (!prolist.Any())
                return new OrmOperateInfo() { Sql = sql, ParaFunc = null };

            string key = $"{tableName}|{sql}|{conStr}";
            OrmOperateInfo cacheInfo = OrmCacheUtil.GetCacheInfo(key);
            if (cacheInfo != null)
                return cacheInfo;
            cacheInfo = new OrmOperateInfo
            {
                Sql = sql,
                ParaFunc = SqlParameterEmit.CreateDicDeleMothed<T>(prolist)
            };
            OrmCacheUtil.AddCacheInfo(key, cacheInfo);

            return cacheInfo;
        }
        #endregion

        #region 执行事务扩展
        /// <summary>
        /// 执行事务扩展
        /// </summary>
        /// <param name="conn">数据库连接</param>
        /// <param name="trans">执行事务的元组对象集合</param>
        /// <param name="commandTimeout">执行超时时间</param>
        /// <returns></returns>
        public static async Task<ResultModel> ExecuteTransactionAsync(this IDbConnection conn, IList<Tuple<string, object>> trans, int? commandTimeout = null)
        {
            if (!trans.Any())
                return new ResultModel((int)ResultType.Failure, "执行事务SQL语句不能为空");

            using (var transaction = conn.BeginTransaction())
            {
                try
                {
                    foreach (var tran in trans)
                    {
                        await conn.ExecuteAsync(tran.Item1, tran.Item2, transaction, commandTimeout);
                    }
                    transaction.Commit();
                    return new ResultModel((int)ResultType.Success);
                }
                catch (Exception ex)
                {
                    transaction.Rollback();
                    return new ResultModel((int)ResultType.Failure, ex.Message);
                }
                finally
                {
                    conn.Close();
                    conn.Dispose();
                }
            }
        }
        #endregion

        #region 转换DbType
        /// <summary>
        /// 转换DbType
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private static DbType GetDbType(object obj)
        {
            if (obj == null)
                return DbType.String;

            string fullName = obj.GetType().FullName;
            switch (fullName)
            {
                case "System.Byte": return DbType.Byte;
                case "System.Int64": return DbType.Int64;
                case "System.Object": return DbType.Binary;
                case "System.Boolean": return DbType.Boolean;
                case "System.String":
                    if (((string)obj).Length <= 1000)
                        return DbType.String;
                    else
                        return DbType.AnsiString;
                case "System.DateTime": return DbType.DateTime;
                case "System.Decimal": return DbType.Decimal;
                case "System.Double": return DbType.Double;
                case "System.Float": return DbType.Double;
                case "System.Int32": return DbType.Int32;
                case "System.Int16": return DbType.Int16;
                case "System.Guid": return DbType.Guid;
                default: return DbType.Object;
            }
        }
        #endregion
    }

    /// <summary>
    /// 操作信息
    /// </summary>
    public class OrmOperateInfo
    {
        /// <summary>
        /// 执行的语句
        /// </summary>
        public string Sql { get; set; }

        /// <summary>
        /// 类型下指定部分字段
        /// </summary>
        public Func<object, Dictionary<string, object>> ParaFunc { get; set; }
    }

    /// <summary>
    /// 缓存
    /// </summary>
    internal static class OrmCacheUtil
    {
        /// <summary>
        /// 缓存集合
        /// </summary>
        private static readonly ConcurrentDictionary<string, OrmOperateInfo> cacheList;

        /// <summary>
        /// 构造函数
        /// </summary>
        static OrmCacheUtil()
        {
            cacheList = new ConcurrentDictionary<string, OrmOperateInfo>();
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public static OrmOperateInfo GetCacheInfo(string key)
        {
            OrmOperateInfo info = new OrmOperateInfo();
            return cacheList.TryGetValue(key, out info) ? info : null;
        }

        /// <summary>
        /// 添加缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="info"></param>
        public static void AddCacheInfo(string key, OrmOperateInfo info)
        {
            cacheList.TryAdd(key, info);
        }
    }
}

