using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DapperExtensions.Lambda;
using DapperExtensions.Mapper;
using Mall.DataAccess;

namespace DapperExtensions.Sql
{
    /// <summary>
    /// Sql生产接口
    /// </summary>
    public interface ISqlGenerator
    {
        /// <summary>
        /// Dapper扩展配置接口
        /// </summary>
        IDapperExtensionConfiguration Configuration { get; }

        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口对象</param>
        /// <param name="sort">排序</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        string Select(IClassMapper classMap, IPredicate predicate, IList<ISort> sort, IDictionary<string, object> parameters);

        /// <summary>
        /// 设置分页查询Sql
        /// </summary>
        /// <param name="sql">sql命令</param>
        /// <param name="page">页码</param>
        /// <param name="resultsPerPage">页大小</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        string SelectPaged(string sql, int page, int resultsPerPage, IDictionary<string, object> parameters);

        /// <summary>
        /// 设置分页查询Sql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口</param>
        /// <param name="sort">排序</param>
        /// <param name="page">页码</param>
        /// <param name="resultsPerPage">页大小</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        string SelectPaged(IClassMapper classMap, IPredicate predicate, IList<ISort> sort, int page, int resultsPerPage, IDictionary<string, object> parameters);

        /// <summary>
        /// 设置查询Sql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口</param>
        /// <param name="sort">排序</param>
        /// <param name="firstResult">最小值</param>
        /// <param name="maxResults">最大值</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        string SelectSet(IClassMapper classMap, IPredicate predicate, IList<ISort> sort, int firstResult, int maxResults, IDictionary<string, object> parameters);

        /// <summary>
        /// 获取统计条数Sql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        string Count(IClassMapper classMap, IPredicate predicate, IDictionary<string, object> parameters);

        /// <summary>
        /// 获取统计条数Sql
        /// </summary>
        /// <param name="sql">sql命令</param>
        /// <returns></returns>
        string PageCount(string sql);

        /// <summary>
        /// 获取InsertSql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <returns></returns>
        string Insert(IClassMapper classMap);

        /// <summary>
        /// 获取UpdateSql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        string Update(IClassMapper classMap, IPredicate predicate, IDictionary<string, object> parameters);

        /// <summary>
        /// 删除Sql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        string Delete(IClassMapper classMap, IPredicate predicate, IDictionary<string, object> parameters);

        /// <summary>
        /// 获取自增sql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <returns></returns>
        string IdentitySql(IClassMapper classMap);

        /// <summary>
        /// 获取表名
        /// </summary>
        /// <param name="map">数据库配置接口对象</param>
        /// <returns></returns>
        string GetTableName(IClassMapper map);

        /// <summary>
        /// 获取表名
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        string GetTableName(string tableName);

        /// <summary>
        /// 获取From表名
        /// </summary>
        /// <param name="map">数据库配置接口对象</param>
        /// <returns></returns>
        string GetFromTableName(IClassMapper map);

        /// <summary>
        /// 获取From表名
        /// </summary>
        /// <param name="schemaName">架构名称</param>
        /// <param name="tableName">表名</param>
        /// <param name="alias">别名</param>
        /// <param name="dbName">数据库名称</param>
        /// <returns></returns>
        string GetFromTableName(string schemaName, string tableName, string alias, string dbName = "");

        /// <summary>
        /// 获取列名
        /// </summary>
        /// <param name="map">数据库配置接口对象</param>
        /// <param name="property">属性对象</param>
        /// <param name="includeAlias">是否包含别名</param>
        /// <returns></returns>
        string GetColumnName(IClassMapper map, IPropertyMap property, bool includeAlias);

        /// <summary>
        /// 获取列名
        /// </summary>
        /// <param name="map">数据库配置接口对象</param>
        /// <param name="propertyName">属性名称</param>
        /// <param name="includeAlias">是否包含别名</param>
        /// <returns></returns>
        string GetColumnName(IClassMapper map, string propertyName, bool includeAlias);

        /// <summary>
        /// 是否支持多条件结构
        /// </summary>
        /// <returns></returns>
        bool SupportsMultipleStatements();

        /// <summary>
        /// 创建查询列
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <returns></returns>
        string BuildSelectColumns(IClassMapper classMap);

        /// <summary>
        /// 创建From
        /// </summary>
        /// <param name="ClassMap">数据库配置接口</param>
        /// <param name="joins">连接</param>
        /// <param name="isEnabledNoLock">是否使用NOLOCK</param>
        /// <returns></returns>

        string BuildFrom(IClassMapper ClassMap, Dictionary<string, KeyValuePair<string, WhereClip>> joins, bool isEnabledNoLock = false);


        /// <summary>
        /// 创建查询列
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="fields">字段</param>
        /// <param name="joins">连接类型</param>
        /// <returns></returns>
        string BuildSelectColumns(IClassMapper classMap, List<Field> fields, Dictionary<string, KeyValuePair<string, WhereClip>> joins);


        /// <summary>
        /// LambdaUpdate
        /// </summary>
        /// <param name="updateHelper">LambdaUpdateHelper</param>
        /// <param name="parameters">parameters</param>
        /// <returns></returns>
        string LambdaUpdate(LambdaUpdateHelper updateHelper, ref Dictionary<string, Parameter> parameters);

        /// <summary>
        /// LambdaSelect
        /// </summary>
        /// <param name="selectHelper">LambdaQuery帮助类对象</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        string LambdaSelect(LambdaQueryHelper selectHelper, ref Dictionary<string, Parameter> parameters);

        /// <summary>
        /// LambdaSelect
        /// </summary>
        /// <param name="selectHelper">LambdaQuery帮助类对象</param>
        /// <param name="parameters">参数</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="loadOrderby">是否加载排序</param>
        /// <returns></returns>
        string LambdaSelect(LambdaQueryHelper selectHelper, ref Dictionary<string, Parameter> parameters, int? pageIndex, int? pageSize, bool loadOrderby = true);

    }

    /// <summary>
    /// 生产接口实现
    /// </summary>
    public class SqlGeneratorImpl : ISqlGenerator
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="configuration">Dapper扩展配置接口</param>
        /// <param name="dbType">数据库类型</param>
        public SqlGeneratorImpl(IDapperExtensionConfiguration configuration, DataBaseType dbType)
        {
            Configuration = configuration;
            DbType = dbType;
        }

        /// <summary>
        /// 数据库类型枚举
        /// </summary>
        public DataBaseType DbType { get; private set; }

        /// <summary>
        /// Dapper扩展配置接口
        /// </summary>
        public IDapperExtensionConfiguration Configuration { get; private set; }

        /// <summary>
        /// 设置查询Sql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口</param>
        /// <param name="sort">排序</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public virtual string Select(IClassMapper classMap, IPredicate predicate, IList<ISort> sort, IDictionary<string, object> parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException("Parameters");
            }

            StringBuilder sql = new StringBuilder(string.Format("SELECT {0} FROM {1}",
                BuildSelectColumns(classMap),
                GetTableName(classMap)));
            if (DbType == DataBaseType.SqlServer)
            {
                sql.Append(" WITH (NOLOCK) ");
            }
            if (predicate != null)
            {
                sql.Append(" WHERE ")
                    .Append(predicate.GetSql(this, parameters, Configuration.Dialect));
            }

            if (sort != null && sort.Any())
            {
                sql.Append(" ORDER BY ")
                    .Append(sort.Select(s => GetColumnName(classMap, s.PropertyName, false) + (s.Ascending ? " ASC" : " DESC")).AppendStrings());
            }

            return sql.ToString();
        }

        /// <summary>
        /// 设置分页查询Sql
        /// </summary>
        /// <param name="sql">sql命令</param>
        /// <param name="page">页码</param>
        /// <param name="resultsPerPage">页大小</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public string SelectPaged(string sql, int page, int resultsPerPage, IDictionary<string, object> parameters)
        {
            string pageSql = Configuration.Dialect.GetPagingSql(sql, page, resultsPerPage, parameters);
            return pageSql;
        }

        /// <summary>
        /// 设置分页查询Sql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口</param>
        /// <param name="sort">排序</param>
        /// <param name="page">页码</param>
        /// <param name="resultsPerPage">页大小</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public virtual string SelectPaged(IClassMapper classMap, IPredicate predicate, IList<ISort> sort, int page, int resultsPerPage, IDictionary<string, object> parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException("Parameters");
            }
            StringBuilder innerSql = new StringBuilder(string.Format("SELECT {0} FROM {1}",
                BuildSelectColumns(classMap),
                GetTableName(classMap)));
            if (predicate != null)
            {
                innerSql.Append(" WHERE ")
                    .Append(predicate.GetSql(this, parameters, Configuration.Dialect));
            }
            if (sort != null && sort.Any())
            {
                string orderBy = sort.Select(s => GetColumnName(classMap, s.PropertyName, false) + (s.Ascending ? " ASC" : " DESC")).AppendStrings();
                innerSql.Append(" ORDER BY " + orderBy);
            }
            string sql = Configuration.Dialect.GetPagingSql(innerSql.ToString(), page, resultsPerPage, parameters);
            return sql;
        }

        /// <summary>
        /// 设置查询Sql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口</param>
        /// <param name="sort">排序</param>
        /// <param name="firstResult">最小值</param>
        /// <param name="maxResults">最大值</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public virtual string SelectSet(IClassMapper classMap, IPredicate predicate, IList<ISort> sort, int firstResult, int maxResults, IDictionary<string, object> parameters)
        {
            if (sort == null || !sort.Any())
            {
                throw new ArgumentNullException("Sort", "Sort cannot be null or empty.");
            }

            if (parameters == null)
            {
                throw new ArgumentNullException("Parameters");
            }

            StringBuilder innerSql = new StringBuilder(string.Format("SELECT {0} FROM {1}",
                BuildSelectColumns(classMap),
                GetTableName(classMap)));
            if (predicate != null)
            {
                innerSql.Append(" WHERE ")
                    .Append(predicate.GetSql(this, parameters, Configuration.Dialect));
            }

            string orderBy = sort.Select(s => GetColumnName(classMap, s.PropertyName, false) + (s.Ascending ? " ASC" : " DESC")).AppendStrings();
            innerSql.Append(" ORDER BY " + orderBy);

            string sql = Configuration.Dialect.GetSetSql(innerSql.ToString(), firstResult, maxResults, parameters);
            return sql;
        }

        /// <summary>
        /// 获取统计条数Sql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public virtual string Count(IClassMapper classMap, IPredicate predicate, IDictionary<string, object> parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException("Parameters");
            }

            StringBuilder sql = new StringBuilder(string.Format("SELECT COUNT(*) {0}Total{1} FROM {2}",
                                Configuration.Dialect.OpenQuote,
                                Configuration.Dialect.CloseQuote,
                                GetTableName(classMap)));
            if (predicate != null)
            {
                sql.Append(" WHERE ")
                    .Append(predicate.GetSql(this, parameters, Configuration.Dialect));
            }

            return sql.ToString();
        }

        /// <summary>
        /// 获取统计条数Sql
        /// </summary>
        /// <param name="sql">sql命令</param>
        /// <returns></returns>
        public virtual string PageCount(string sql)
        {
            if (string.IsNullOrEmpty(sql))
            {
                throw new ArgumentNullException("Parameters");
            }

            StringBuilder sqlCount = new StringBuilder();
            sqlCount.Append(string.Format("SELECT COUNT(*) AS {0}Total{1} FROM ({2}) {0}TempCountData{1}",
                                     Configuration.Dialect.OpenQuote,
                                     Configuration.Dialect.CloseQuote,
                                     sql));


            return sqlCount.ToString();
        }


        /// <summary>
        /// 获取InsertSql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <returns></returns>
        public virtual string Insert(IClassMapper classMap)
        {
            var columns = classMap.Properties.Where(p => !(p.Value.Ignored || p.Value.IsReadOnly || p.Value.KeyType == KeyType.Identity));
            if (!columns.Any())
            {
                throw new ArgumentException("No columns were mapped.");
            }

            var columnNames = columns.Select(p => GetColumnName(classMap, p.Value, false));
            var parameters = columns.Select(p => Configuration.Dialect.ParameterPrefix + p.Value.Name);

            string sql = string.Format("INSERT INTO {0} ({1}) VALUES ({2})",
                                       GetTableName(classMap),
                                       columnNames.AppendStrings(),
                                       parameters.AppendStrings());
            return sql;
        }

        /// <summary>
        /// 获取UpdateSql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public virtual string Update(IClassMapper classMap, IPredicate predicate, IDictionary<string, object> parameters)
        {
            if (predicate == null)
            {
                throw new ArgumentNullException("Predicate");
            }

            if (parameters == null)
            {
                throw new ArgumentNullException("Parameters");
            }

            var columns = classMap.Properties.Where(p => !(p.Value.Ignored || p.Value.IsReadOnly || p.Value.KeyType == KeyType.Identity));
            if (!columns.Any())
            {
                throw new ArgumentException("No columns were mapped.");
            }

            var setSql =
                columns.Select(
                    p =>
                    string.Format(
                        "{0} = {1}{2}", GetColumnName(classMap, p.Value, false), Configuration.Dialect.ParameterPrefix, p.Value.Name));
            return string.Format("UPDATE {0} SET {1} WHERE {2}",
                GetTableName(classMap),
                setSql.AppendStrings(),
                predicate.GetSql(this, parameters, Configuration.Dialect));
        }

        /// <summary>
        /// 删除Sql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="predicate">谓词接口</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public virtual string Delete(IClassMapper classMap, IPredicate predicate, IDictionary<string, object> parameters)
        {
            if (predicate == null)
            {
                throw new ArgumentNullException("Predicate");
            }
            if (parameters == null)
            {
                throw new ArgumentNullException("Parameters");
            }
            StringBuilder sql = new StringBuilder(string.Format("DELETE FROM {0}", GetTableName(classMap)));
            sql.Append(" WHERE ").Append(predicate.GetSql(this, parameters, Configuration.Dialect));
            return sql.ToString();
        }

        /// <summary>
        /// 获取自增sql
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <returns></returns>
        public virtual string IdentitySql(IClassMapper classMap)
        {
            return Configuration.Dialect.GetIdentitySql(GetTableName(classMap));
        }

        /// <summary>
        /// 获取表名
        /// </summary>
        /// <param name="map">数据库配置接口对象</param>
        /// <returns></returns>
        public virtual string GetTableName(IClassMapper map)
        {
            return Configuration.Dialect.GetTableName(map.SchemaName, map.TableName, null);
        }

        /// <summary>
        /// 获取From表名
        /// </summary>
        /// <param name="map">数据库配置接口对象</param>
        /// <returns></returns>
        public string GetFromTableName(IClassMapper map)
        {
            return Configuration.Dialect.GetTableName(map.SchemaName, map.TableName, null, map.DbName);
        }

        /// <summary>
        /// 获取From表名
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        public virtual string GetTableName(string tableName)
        {
            return Configuration.Dialect.GetTableName("", tableName, null);
        }

        /// <summary>
        /// 获取From表名
        /// </summary>
        /// <param name="schemaName">架构名称</param>
        /// <param name="tableName">表名</param>
        /// <param name="alias">别名</param>
        /// <param name="dbName">数据库名称</param>
        /// <returns></returns>
        public virtual string GetFromTableName(string schemaName, string tableName, string alias, string dbName = "")
        {
            return Configuration.Dialect.GetTableName(schemaName, tableName, alias, dbName);
        }

        /// <summary>
        /// 获取列名
        /// </summary>
        /// <param name="map">数据库配置接口对象</param>
        /// <param name="property">属性对象</param>
        /// <param name="includeAlias">是否包含别名</param>
        /// <returns></returns>
        public virtual string GetColumnName(IClassMapper map, IPropertyMap property, bool includeAlias)
        {
            string alias = null;
            if (property.ColumnName != property.Name && includeAlias)
            {
                alias = property.Name;
            }

            return Configuration.Dialect.GetColumnName(GetTableName(map.TableName), property.ColumnName, alias);
        }

        /// <summary>
        /// 获取列名
        /// </summary>
        /// <param name="map">数据库配置接口对象</param>
        /// <param name="propertyName">属性名称</param>
        /// <param name="includeAlias">是否包含别名</param>
        /// <returns></returns>
        public virtual string GetColumnName(IClassMapper map, string propertyName, bool includeAlias)
        {
            IPropertyMap propertyMap = map.Properties.SingleOrDefault(p => p.Value.Name.Equals(propertyName, StringComparison.InvariantCultureIgnoreCase)).Value;
            if (propertyMap == null)
            {
                throw new ArgumentException(string.Format("Could not find '{0}' in Mapping.", propertyName));
            }

            return GetColumnName(map, propertyMap, includeAlias);
        }

        /// <summary>
        /// 是否支持多条件结构
        /// </summary>
        /// <returns></returns>
        public virtual bool SupportsMultipleStatements()
        {
            return Configuration.Dialect.SupportsMultipleStatements;
        }

        /// <summary>
        /// 创建查询列
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <returns></returns>
        public virtual string BuildSelectColumns(IClassMapper classMap)
        {
            var columns = classMap.Properties
                .Where(p => !p.Value.Ignored)
                .Select(p => GetColumnName(classMap, p.Value, true));
            return columns.AppendStrings();
        }


        /// <summary>
        /// LambdaUpdate
        /// </summary>
        /// <param name="updateHelper">LambdaUpdate帮助类对象</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public virtual string LambdaUpdate(LambdaUpdateHelper updateHelper, ref Dictionary<string, Parameter> parameters)
        {
            StringBuilder sql = new StringBuilder();
            sql.Append("UPDATE ");
            sql.Append(GetTableName(updateHelper.ClassMap.TableName));

            if (!WhereClip.IsNullOrEmpty(updateHelper.SetClip))
            {
                sql.Append(updateHelper.SetClip.SetString);
            }
            else
            {
                throw new Exception("Update 语句中未找到 Set 的字段信息");
            }

            if (!WhereClip.IsNullOrEmpty(updateHelper.WhereClip))
            {
                sql.Append(updateHelper.WhereClip.WhereString);
            }
            return sql.ToString();
        }

        /// <summary>
        /// LambdaSelect
        /// </summary>
        /// <param name="selectHelper">LambdaQuery帮助类对象</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public virtual string LambdaSelect(LambdaQueryHelper selectHelper, ref Dictionary<string, Parameter> parameters)
        {
            string topSql = this.Configuration.Dialect.GetTopString(Convert.ToInt32(selectHelper.PageIndex), Convert.ToInt32(selectHelper.PageSize));
            StringBuilder sql = new StringBuilder();
            sql.Append("SELECT ");
            if (!string.IsNullOrEmpty(selectHelper.DistinctString))
            {
                sql.Append(selectHelper.DistinctString);
                sql.Append(" ");
            }
            sql.Append(topSql);
            sql.Append(BuildSelectColumns(selectHelper.ClassMap, selectHelper.Fields, selectHelper.Joins));
            sql.Append(" FROM ");
            sql.Append(BuildFrom(selectHelper.ClassMap, selectHelper.Joins, selectHelper.EnabledNoLock));
            sql.Append(" ");

            if (!WhereClip.IsNullOrEmpty(selectHelper.WhereClip))
            {
                sql.Append(selectHelper.WhereClip.WhereString);
            }
            if (!GroupByClip.IsNullOrEmpty(selectHelper.GroupByClip))
            {
                sql.Append(selectHelper.GroupByClip.GroupByString);
                if (!WhereClip.IsNullOrEmpty(selectHelper.HavingClip))
                {
                    sql.Append(" HAVING ");
                    sql.Append(selectHelper.HavingClip.ToString());
                }
            }
            if (!OrderByClip.IsNullOrEmpty(selectHelper.OrderByClip))
            {
                sql.Append(selectHelper.OrderByClip.OrderByString);
                sql.Append(" ");
            }

            if (selectHelper.PageIndex > 0 && selectHelper.PageSize > 0 && string.IsNullOrEmpty(topSql))
            {
                Dictionary<string, object> pageParameters = new Dictionary<string, object>();
                string pageSql = this.Configuration.Dialect.GetPagingSql(sql.ToString(), Convert.ToInt32(selectHelper.PageIndex), Convert.ToInt32(selectHelper.PageSize), pageParameters);
                foreach (var item in pageParameters)
                {
                    if (!parameters.ContainsKey(item.Key))
                    {
                        parameters.Add(item.Key, new Parameter(item.Key, item.Value));
                    }
                }
                return pageSql;
            }
            return sql.ToString();
        }

        /// <summary>
        /// 创建From
        /// </summary>
        /// <param name="ClassMap">数据库配置接口</param>
        /// <param name="joins">连接</param>
        /// <param name="isEnabledNoLock">是否使用NOLOCK</param>
        /// <returns></returns>

        public virtual string BuildFrom(IClassMapper ClassMap, Dictionary<string, KeyValuePair<string, WhereClip>> joins, bool isEnabledNoLock = false)
        {
            StringBuilder fromstring = new StringBuilder();
            fromstring.Append(GetFromTableName(ClassMap));
            if (isEnabledNoLock)
            {
                fromstring.Append(" WITH (NOLOCK) ");
            }
            foreach (KeyValuePair<string, KeyValuePair<string, WhereClip>> kv in joins)
            {
                fromstring.Append(" ");
                fromstring.Append(kv.Value.Key);
                fromstring.Append(" ");
                fromstring.Append(kv.Key);
                if (isEnabledNoLock)
                {
                    fromstring.Append(" WITH (NOLOCK)");
                }
                fromstring.Append(" ON ");
                fromstring.Append(kv.Value.Value.ToString());
            }
            return fromstring.ToString();
        }

        /// <summary>
        /// 创建查询列
        /// </summary>
        /// <param name="classMap">数据库配置接口对象</param>
        /// <param name="fields">字段</param>
        /// <param name="joins">连接类型</param>
        /// <returns></returns>
        public virtual string BuildSelectColumns(IClassMapper classMap, List<Field> fields, Dictionary<string, KeyValuePair<string, WhereClip>> joins)
        {
            if (fields.Count == 0)
            {
                if (joins.Count > 0)
                {
                    return "*";
                }
                else
                {
                    return BuildSelectColumns(classMap);
                }
            }
            StringBuilder columns = new StringBuilder();
            foreach (Field filed in fields)
            {
                columns.Append(",");
                columns.Append(Configuration.Dialect.GetColumnName(GetTableName(filed.TableName), filed.ColumnName, filed.AliasName));
            }
            return columns.ToString().Substring(1);
        }

        /// <summary>
        /// LambdaSelect
        /// </summary>
        /// <param name="selectHelper">LambdaQuery帮助类对象</param>
        /// <param name="parameters">参数</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="loadOrderby">是否加载排序</param>
        /// <returns></returns>
        public virtual string LambdaSelect(LambdaQueryHelper selectHelper, ref Dictionary<string, Parameter> parameters, int? pageIndex, int? pageSize, bool loadOrderby = true)
        {
            {
                string topSql = this.Configuration.Dialect.GetTopString(Convert.ToInt32(pageIndex), Convert.ToInt32(pageSize));
                StringBuilder sql = new StringBuilder();
                sql.Append("SELECT ");
                if (!string.IsNullOrEmpty(selectHelper.DistinctString))
                {
                    sql.Append(selectHelper.DistinctString);
                    sql.Append(" ");
                }
                sql.Append(topSql);
                sql.Append(BuildSelectColumns(selectHelper.ClassMap, selectHelper.Fields, selectHelper.Joins));
                sql.Append(" FROM ");
                sql.Append(BuildFrom(selectHelper.ClassMap, selectHelper.Joins, selectHelper.EnabledNoLock));
                sql.Append(" ");

                if (!WhereClip.IsNullOrEmpty(selectHelper.WhereClip))
                {
                    sql.Append(selectHelper.WhereClip.WhereString);
                }
                if (!GroupByClip.IsNullOrEmpty(selectHelper.GroupByClip))
                {
                    sql.Append(selectHelper.GroupByClip.GroupByString);
                    if (!WhereClip.IsNullOrEmpty(selectHelper.HavingClip))
                    {
                        sql.Append(" HAVING ");
                        sql.Append(selectHelper.HavingClip.ToString());
                    }
                }
                if (loadOrderby && !OrderByClip.IsNullOrEmpty(selectHelper.OrderByClip))
                {
                    sql.Append(selectHelper.OrderByClip.OrderByString);
                    sql.Append(" ");
                }

                if (pageIndex != null && pageSize != null && string.IsNullOrEmpty(topSql))
                {
                    Dictionary<string, object> pageParameters = new Dictionary<string, object>();
                    string pageSql = this.Configuration.Dialect.GetPagingSql(sql.ToString(), Convert.ToInt32(pageIndex), Convert.ToInt32(pageSize), pageParameters);
                    foreach (var item in pageParameters)
                    {
                        if (!parameters.ContainsKey(item.Key))
                        {
                            parameters.Add(item.Key, new Parameter(item.Key, item.Value));
                        }
                    }
                    return pageSql;
                }
                return sql.ToString();
            }
        }
    }
}