mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	- 调整 ISelect linq to sql 和 queryable 实现依赖移至 FreeSql.Extensions.Linq;#260
This commit is contained in:
		@@ -1,17 +1,18 @@
 | 
			
		||||
using FreeSql.Internal.Model;
 | 
			
		||||
using FreeSql.DataAnnotations;
 | 
			
		||||
using FreeSql.Internal.CommonProvider;
 | 
			
		||||
using FreeSql.Internal.Model;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Data.Common;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
using FreeSql.DataAnnotations;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal
 | 
			
		||||
{
 | 
			
		||||
@@ -19,8 +20,8 @@ namespace FreeSql.Internal
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        public CommonUtils _common;
 | 
			
		||||
        public CommonProvider.AdoProvider _ado => _adoPriv ?? (_adoPriv = _common._orm.Ado as CommonProvider.AdoProvider);
 | 
			
		||||
        CommonProvider.AdoProvider _adoPriv;
 | 
			
		||||
        public AdoProvider _ado => _adoPriv ?? (_adoPriv = _common._orm.Ado as AdoProvider);
 | 
			
		||||
        AdoProvider _adoPriv;
 | 
			
		||||
        public CommonExpression(CommonUtils common)
 | 
			
		||||
        {
 | 
			
		||||
            _common = common;
 | 
			
		||||
@@ -692,14 +693,6 @@ namespace FreeSql.Internal
 | 
			
		||||
                    }
 | 
			
		||||
                    if (callType.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`"))
 | 
			
		||||
                    {
 | 
			
		||||
                        //if (exp3.Type == typeof(string) && exp3.Arguments.Any() && exp3.Arguments[0].NodeType == ExpressionType.Constant) {
 | 
			
		||||
                        //	switch (exp3.Method.Name) {
 | 
			
		||||
                        //		case "Sum": return $"sum({(exp3.Arguments[0] as ConstantExpression)?.Value})";
 | 
			
		||||
                        //		case "Avg": return $"avg({(exp3.Arguments[0] as ConstantExpression)?.Value})";
 | 
			
		||||
                        //		case "Max": return $"max({(exp3.Arguments[0] as ConstantExpression)?.Value})";
 | 
			
		||||
                        //		case "Min": return $"min({(exp3.Arguments[0] as ConstantExpression)?.Value})";
 | 
			
		||||
                        //	}
 | 
			
		||||
                        //}
 | 
			
		||||
                        switch (exp3.Method.Name)
 | 
			
		||||
                        {
 | 
			
		||||
                            case "Count": return exp3.Arguments.Count == 0 ? "count(1)" : $"count({ExpressionLambdaToSql(exp3.Arguments[0], tsc)})";
 | 
			
		||||
@@ -819,11 +812,10 @@ namespace FreeSql.Internal
 | 
			
		||||
                                        if (fsql == null) fsql = Expression.Lambda(exp3tmp).Compile().DynamicInvoke();
 | 
			
		||||
                                        fsqlType = fsql?.GetType();
 | 
			
		||||
                                        if (fsqlType == null) break;
 | 
			
		||||
                                        if (exp3.Method.Name != "ToList")
 | 
			
		||||
                                            fsqlType.GetField("_limit", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(fsql, 1);
 | 
			
		||||
                                        if (tsc.dbParams != null)
 | 
			
		||||
                                            fsqlType.GetField("_params", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(fsql, tsc.dbParams);
 | 
			
		||||
                                        fsqltables = fsqlType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(fsql) as List<SelectTableInfo>;
 | 
			
		||||
                                        var fsqlSelect0 = fsql as Select0Provider;
 | 
			
		||||
                                        if (exp3.Method.Name != "ToList") fsqlSelect0._limit = 1;
 | 
			
		||||
                                        if (tsc.dbParams != null) fsqlSelect0._params = tsc.dbParams;
 | 
			
		||||
                                        fsqltables = fsqlSelect0._tables;
 | 
			
		||||
                                        //fsqltables[0].Alias = $"{tsc._tables[0].Alias}_{fsqltables[0].Alias}";
 | 
			
		||||
                                        if (fsqltables != tsc._tables)
 | 
			
		||||
                                            fsqltables.AddRange(tsc._tables.Select(a => new SelectTableInfo
 | 
			
		||||
@@ -836,7 +828,7 @@ namespace FreeSql.Internal
 | 
			
		||||
                                            }));
 | 
			
		||||
                                        if (tsc.whereCascadeExpression?.Any() == true)
 | 
			
		||||
                                        {
 | 
			
		||||
                                            var fsqlCascade = fsqlType.GetField("_whereCascadeExpression", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(fsql) as List<LambdaExpression>;
 | 
			
		||||
                                            var fsqlCascade = fsqlSelect0._whereCascadeExpression;
 | 
			
		||||
                                            if (fsqlCascade != tsc.whereCascadeExpression)
 | 
			
		||||
                                                fsqlCascade.AddRange(tsc.whereCascadeExpression);
 | 
			
		||||
                                        }
 | 
			
		||||
@@ -1022,12 +1014,6 @@ namespace FreeSql.Internal
 | 
			
		||||
                                break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    //var eleType = callType.GetElementType() ?? callType.GenericTypeArguments.FirstOrDefault();
 | 
			
		||||
                    //if (eleType != null && typeof(IEnumerable<>).MakeGenericType(eleType).IsAssignableFrom(callType)) { //集合导航属性子查询
 | 
			
		||||
                    //	if (exp3.Method.Name == "Any") { //exists
 | 
			
		||||
 | 
			
		||||
                    //	}
 | 
			
		||||
                    //}
 | 
			
		||||
                    other3Exp = ExpressionLambdaToSqlOther(exp3, tsc);
 | 
			
		||||
                    if (string.IsNullOrEmpty(other3Exp) == false) return other3Exp;
 | 
			
		||||
                    if (exp3.IsParameter() == false) return formatSql(Expression.Lambda(exp3).Compile().DynamicInvoke(), tsc.mapType, tsc.mapColumnTmp, tsc.dbParams);
 | 
			
		||||
@@ -1107,7 +1093,10 @@ namespace FreeSql.Internal
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case ExpressionType.MemberAccess:
 | 
			
		||||
                                    var expStackFirstMem = expStack.First() as MemberExpression;
 | 
			
		||||
                                    if (expStackFirstMem.Expression?.NodeType == ExpressionType.Constant) firstValue = (expStackFirstMem.Expression as ConstantExpression)?.Value;
 | 
			
		||||
                                    if (expStackFirstMem.Expression?.NodeType == ExpressionType.Constant) 
 | 
			
		||||
                                        firstValue = (expStackFirstMem.Expression as ConstantExpression)?.Value;
 | 
			
		||||
                                    else
 | 
			
		||||
                                        return formatSql(Expression.Lambda(exp).Compile().DynamicInvoke(), tsc.mapType, tsc.mapColumnTmp, tsc.dbParams);
 | 
			
		||||
                                    break;
 | 
			
		||||
                            }
 | 
			
		||||
                            while (expStack.Any())
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,6 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
 | 
			
		||||
    public abstract partial class CodeFirstProvider : ICodeFirst
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        public IFreeSql _orm;
 | 
			
		||||
        public CommonUtils _commonUtils;
 | 
			
		||||
        public CommonExpression _commonExpression;
 | 
			
		||||
@@ -78,7 +77,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
                        _dicSynced.TryAdd(entityType, trydic = new ConcurrentDictionary<string, bool>());
 | 
			
		||||
            return trydic;
 | 
			
		||||
        }
 | 
			
		||||
        internal void _dicSycedTryAdd(Type entityType, string tableName = null) =>
 | 
			
		||||
        public void _dicSycedTryAdd(Type entityType, string tableName = null) =>
 | 
			
		||||
            _dicSycedGetOrAdd(entityType).TryAdd(GetTableNameLowerOrUpper(tableName), true);
 | 
			
		||||
 | 
			
		||||
        public void SyncStructure<TEntity>() =>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,107 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
{
 | 
			
		||||
    class QueryableProvider<T> : IQueryable<T>
 | 
			
		||||
    {
 | 
			
		||||
        private Expression _expression;
 | 
			
		||||
        private IQueryProvider _provider;
 | 
			
		||||
        private object _select;
 | 
			
		||||
        private CommonExpression _commonExpression;
 | 
			
		||||
 | 
			
		||||
        public QueryableProvider(object select)
 | 
			
		||||
        {
 | 
			
		||||
            _select = select;
 | 
			
		||||
            _commonExpression = _select.GetType().GetField("_commonExpression", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(_select) as CommonExpression;
 | 
			
		||||
            _expression = Expression.Constant(this);
 | 
			
		||||
            _provider = new QueryProvider<T>(_select, _commonExpression);
 | 
			
		||||
        }
 | 
			
		||||
        public QueryableProvider(Expression expression, IQueryProvider provider, object select, CommonExpression commonExpression)
 | 
			
		||||
        {
 | 
			
		||||
            _select = select;
 | 
			
		||||
            _commonExpression = commonExpression;
 | 
			
		||||
            _expression = expression;
 | 
			
		||||
            _provider = provider;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerator<T> GetEnumerator()
 | 
			
		||||
        {
 | 
			
		||||
            var result = _provider.Execute<List<T>>(_expression);
 | 
			
		||||
            if (result == null)
 | 
			
		||||
                yield break;
 | 
			
		||||
            foreach (var item in result)
 | 
			
		||||
            {
 | 
			
		||||
                yield return item;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
 | 
			
		||||
 | 
			
		||||
        public Type ElementType => typeof(QueryableProvider<T>);
 | 
			
		||||
        public Expression Expression => _expression;
 | 
			
		||||
        public IQueryProvider Provider => _provider;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class QueryProvider<T> : IQueryProvider
 | 
			
		||||
    {
 | 
			
		||||
        private object _select;
 | 
			
		||||
        private CommonExpression _commonExpression;
 | 
			
		||||
 | 
			
		||||
        public QueryProvider(object select, CommonExpression commonExpression)
 | 
			
		||||
        {
 | 
			
		||||
            _select = select;
 | 
			
		||||
            _commonExpression = commonExpression;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
 | 
			
		||||
        {
 | 
			
		||||
            IQueryable<TElement> query = new QueryableProvider<TElement>(expression, this, _select, _commonExpression);
 | 
			
		||||
            return query;
 | 
			
		||||
        }
 | 
			
		||||
        public IQueryable CreateQuery(Expression expression) => throw new NotImplementedException();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public TResult Execute<TResult>(Expression expression)
 | 
			
		||||
        {
 | 
			
		||||
            var methodExp = expression as MethodCallExpression;
 | 
			
		||||
            while (methodExp != null)
 | 
			
		||||
            {
 | 
			
		||||
                switch (methodExp.Method.Name)
 | 
			
		||||
                {
 | 
			
		||||
                    case "First":
 | 
			
		||||
                    case "FirstOrDefault":
 | 
			
		||||
                        _select.GetType().GetMethod("Limit", new[] { typeof(int) }).Invoke(_select, new object[] { 1 });
 | 
			
		||||
                        break;
 | 
			
		||||
                    default:
 | 
			
		||||
                        var selectMethod = _select.GetType().GetMethod(methodExp.Method.Name, methodExp.Arguments.Where((a, b) => b > 0).Select(a => a.Type).ToArray());
 | 
			
		||||
                        if (selectMethod == null) throw new Exception($"无法找到 ISelect.{methodExp.Method.Name}({string.Join(", ", methodExp.Arguments.Select(a => a.Type.FullName))}) 方法");
 | 
			
		||||
 | 
			
		||||
                        var selectArgs = methodExp.Arguments.Where((a, b) => b > 0).Select(a =>
 | 
			
		||||
                        {
 | 
			
		||||
                            switch (a.NodeType)
 | 
			
		||||
                            {
 | 
			
		||||
                                case ExpressionType.Lambda: return (object)a;
 | 
			
		||||
                                default: return Expression.Lambda(a).Compile().DynamicInvoke();
 | 
			
		||||
                            }
 | 
			
		||||
                        }).ToArray();
 | 
			
		||||
                        selectMethod.Invoke(_select, selectArgs);
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
                methodExp = methodExp.Arguments.FirstOrDefault() as MethodCallExpression;
 | 
			
		||||
            }
 | 
			
		||||
            var resultType = typeof(TResult);
 | 
			
		||||
            var resultTypeIsList = typeof(IList).IsAssignableFrom(resultType);
 | 
			
		||||
            if (resultTypeIsList) resultType = resultType.GetGenericArguments()[0];
 | 
			
		||||
            var ret = _select.GetType().GetMethod(resultTypeIsList ? "ToList" : "First", new Type[0])
 | 
			
		||||
                .MakeGenericMethod(resultType)
 | 
			
		||||
                .Invoke(_select, new object[0]);
 | 
			
		||||
            return (TResult)ret;
 | 
			
		||||
        }
 | 
			
		||||
        public object Execute(Expression expression) => throw new NotImplementedException();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -16,33 +16,32 @@ using System.Threading.Tasks;
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    public abstract partial class Select0Provider<TSelect, T1> : ISelect0<TSelect, T1> where TSelect : class where T1 : class
 | 
			
		||||
    public abstract partial class Select0Provider
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        protected int _limit, _skip;
 | 
			
		||||
        protected string _select = "SELECT ", _orderby, _groupby, _having;
 | 
			
		||||
        protected StringBuilder _where = new StringBuilder();
 | 
			
		||||
        protected List<DbParameter> _params = new List<DbParameter>();
 | 
			
		||||
        internal protected List<SelectTableInfo> _tables = new List<SelectTableInfo>();
 | 
			
		||||
        protected List<Func<Type, string, string>> _tableRules = new List<Func<Type, string, string>>();
 | 
			
		||||
        protected Func<Type, string, string> _aliasRule;
 | 
			
		||||
        protected string _tosqlAppendContent;
 | 
			
		||||
        protected StringBuilder _join = new StringBuilder();
 | 
			
		||||
        internal protected IFreeSql _orm;
 | 
			
		||||
        protected CommonUtils _commonUtils;
 | 
			
		||||
        protected CommonExpression _commonExpression;
 | 
			
		||||
        protected DbTransaction _transaction;
 | 
			
		||||
        protected DbConnection _connection;
 | 
			
		||||
        internal protected Action<object> _trackToList;
 | 
			
		||||
        internal protected List<Action<object>> _includeToList = new List<Action<object>>();
 | 
			
		||||
        public int _limit, _skip;
 | 
			
		||||
        public string _select = "SELECT ", _orderby, _groupby, _having;
 | 
			
		||||
        public StringBuilder _where = new StringBuilder();
 | 
			
		||||
        public List<DbParameter> _params = new List<DbParameter>();
 | 
			
		||||
        public List<SelectTableInfo> _tables = new List<SelectTableInfo>();
 | 
			
		||||
        public List<Func<Type, string, string>> _tableRules = new List<Func<Type, string, string>>();
 | 
			
		||||
        public Func<Type, string, string> _aliasRule;
 | 
			
		||||
        public string _tosqlAppendContent;
 | 
			
		||||
        public StringBuilder _join = new StringBuilder();
 | 
			
		||||
        public IFreeSql _orm;
 | 
			
		||||
        public CommonUtils _commonUtils;
 | 
			
		||||
        public CommonExpression _commonExpression;
 | 
			
		||||
        public DbTransaction _transaction;
 | 
			
		||||
        public DbConnection _connection;
 | 
			
		||||
        public Action<object> _trackToList;
 | 
			
		||||
        public List<Action<object>> _includeToList = new List<Action<object>>();
 | 
			
		||||
#if net40
 | 
			
		||||
#else
 | 
			
		||||
        protected List<Func<object, Task>> _includeToListAsync = new List<Func<object, Task>>();
 | 
			
		||||
        public List<Func<object, Task>> _includeToListAsync = new List<Func<object, Task>>();
 | 
			
		||||
#endif
 | 
			
		||||
        protected bool _distinct;
 | 
			
		||||
        protected Expression _selectExpression;
 | 
			
		||||
        protected List<LambdaExpression> _whereCascadeExpression = new List<LambdaExpression>();
 | 
			
		||||
        protected List<GlobalFilter.Item> _whereGlobalFilter;
 | 
			
		||||
        public bool _distinct;
 | 
			
		||||
        public Expression _selectExpression;
 | 
			
		||||
        public List<LambdaExpression> _whereCascadeExpression = new List<LambdaExpression>();
 | 
			
		||||
        public List<GlobalFilter.Item> _whereGlobalFilter;
 | 
			
		||||
 | 
			
		||||
        int _disposeCounter;
 | 
			
		||||
        ~Select0Provider()
 | 
			
		||||
@@ -64,24 +63,25 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
            _whereGlobalFilter = _orm.GlobalFilter.GetFilters();
 | 
			
		||||
            _whereCascadeExpression.AddRange(_whereGlobalFilter.Select(a => a.Where));
 | 
			
		||||
        }
 | 
			
		||||
        public static void CopyData(Select0Provider<TSelect, T1> from, object to, ReadOnlyCollection<ParameterExpression> lambParms)
 | 
			
		||||
 | 
			
		||||
        public static void CopyData(Select0Provider from, Select0Provider to, ReadOnlyCollection<ParameterExpression> lambParms)
 | 
			
		||||
        {
 | 
			
		||||
            var toType = to?.GetType();
 | 
			
		||||
            if (toType == null) return;
 | 
			
		||||
            toType.GetField("_limit", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._limit);
 | 
			
		||||
            toType.GetField("_skip", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._skip);
 | 
			
		||||
            toType.GetField("_select", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._select);
 | 
			
		||||
            toType.GetField("_orderby", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._orderby);
 | 
			
		||||
            toType.GetField("_groupby", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._groupby);
 | 
			
		||||
            toType.GetField("_having", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._having);
 | 
			
		||||
            toType.GetField("_where", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new StringBuilder().Append(from._where.ToString()));
 | 
			
		||||
            toType.GetField("_params", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<DbParameter>(from._params.ToArray()));
 | 
			
		||||
            if (to == null) return;
 | 
			
		||||
            to._limit = from._limit;
 | 
			
		||||
            to._skip = from._skip;
 | 
			
		||||
            to._select = from._select;
 | 
			
		||||
            to._orderby = from._orderby;
 | 
			
		||||
            to._groupby = from._groupby;
 | 
			
		||||
            to._having = from._having;
 | 
			
		||||
            to._where = new StringBuilder().Append(from._where.ToString());
 | 
			
		||||
            to._params = new List<DbParameter>(from._params.ToArray());
 | 
			
		||||
 | 
			
		||||
            if (lambParms == null)
 | 
			
		||||
                toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<SelectTableInfo>(from._tables.ToArray()));
 | 
			
		||||
                to._tables = new List<SelectTableInfo>(from._tables.ToArray());
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var findedIndexs = new List<int>();
 | 
			
		||||
                var _multiTables = toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(to) as List<SelectTableInfo>;
 | 
			
		||||
                var _multiTables = to._tables;
 | 
			
		||||
                _multiTables[0] = from._tables[0];
 | 
			
		||||
                for (var a = 1; a < lambParms.Count; a++)
 | 
			
		||||
                {
 | 
			
		||||
@@ -103,26 +103,29 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
                    _multiTables.Add(from._tables[a]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            toType.GetField("_tableRules", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<Func<Type, string, string>>(from._tableRules.ToArray()));
 | 
			
		||||
            toType.GetField("_aliasRule", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._aliasRule);
 | 
			
		||||
            toType.GetField("_join", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new StringBuilder().Append(from._join.ToString()));
 | 
			
		||||
            //toType.GetField("_orm", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._orm);
 | 
			
		||||
            //toType.GetField("_commonUtils", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._commonUtils);
 | 
			
		||||
            //toType.GetField("_commonExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._commonExpression);
 | 
			
		||||
            toType.GetField("_transaction", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._transaction);
 | 
			
		||||
            toType.GetField("_connection", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._connection);
 | 
			
		||||
            toType.GetField("_trackToList", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._trackToList);
 | 
			
		||||
            toType.GetField("_includeToList", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<Action<object>>(from._includeToList.ToArray()));
 | 
			
		||||
            to._tableRules = new List<Func<Type, string, string>>(from._tableRules.ToArray());
 | 
			
		||||
            to._aliasRule = from._aliasRule;
 | 
			
		||||
            to._join = new StringBuilder().Append(from._join.ToString());
 | 
			
		||||
            //to._orm = from._orm;
 | 
			
		||||
            //to._commonUtils = from._commonUtils;
 | 
			
		||||
            //to._commonExpression = from._commonExpression;
 | 
			
		||||
            to._transaction = from._transaction;
 | 
			
		||||
            to._connection = from._connection;
 | 
			
		||||
            to._trackToList = from._trackToList;
 | 
			
		||||
            to._includeToList = new List<Action<object>>(from._includeToList.ToArray());
 | 
			
		||||
#if net40
 | 
			
		||||
#else
 | 
			
		||||
            toType.GetField("_includeToListAsync", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<Func<object, Task>>(from._includeToListAsync.ToArray()));
 | 
			
		||||
            to._includeToListAsync = new List<Func<object, Task>>(from._includeToListAsync.ToArray());
 | 
			
		||||
#endif
 | 
			
		||||
            toType.GetField("_distinct", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._distinct);
 | 
			
		||||
            toType.GetField("_selectExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._selectExpression);
 | 
			
		||||
            toType.GetField("_whereCascadeExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<LambdaExpression>(from._whereCascadeExpression.ToArray()));
 | 
			
		||||
            toType.GetField("_whereGlobalFilter", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<GlobalFilter.Item>(from._whereGlobalFilter.ToArray()));
 | 
			
		||||
            to._distinct = from._distinct;
 | 
			
		||||
            to._selectExpression = from._selectExpression;
 | 
			
		||||
            to._whereCascadeExpression = new List<LambdaExpression>(from._whereCascadeExpression.ToArray());
 | 
			
		||||
            to._whereGlobalFilter = new List<GlobalFilter.Item>(from._whereGlobalFilter.ToArray());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public abstract partial class Select0Provider<TSelect, T1> : Select0Provider, ISelect0<TSelect, T1> where TSelect : class where T1 : class
 | 
			
		||||
    {
 | 
			
		||||
        public Select0Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
 | 
			
		||||
        {
 | 
			
		||||
            _orm = orm;
 | 
			
		||||
@@ -1082,7 +1085,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
        protected TMember InternalMin<TMember>(Expression exp) => this.ToList<TMember>($"min({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}").Min();
 | 
			
		||||
        protected decimal InternalSum(Expression exp) => this.ToList<decimal>($"sum({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}").Sum();
 | 
			
		||||
 | 
			
		||||
        protected ISelectGrouping<TKey, TValue> InternalGroupBy<TKey, TValue>(Expression columns)
 | 
			
		||||
        public ISelectGrouping<TKey, TValue> InternalGroupBy<TKey, TValue>(Expression columns)
 | 
			
		||||
        {
 | 
			
		||||
            var map = new ReadAnonymousTypeInfo();
 | 
			
		||||
            var field = new StringBuilder();
 | 
			
		||||
@@ -1093,7 +1096,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
            this.GroupBy(sql.Length > 0 ? sql.Substring(2) : null);
 | 
			
		||||
            return new SelectGroupingProvider<TKey, TValue>(_orm, this, map, sql, _commonExpression, _tables);
 | 
			
		||||
        }
 | 
			
		||||
        protected TSelect InternalJoin(Expression exp, SelectTableInfoType joinType)
 | 
			
		||||
        public TSelect InternalJoin(Expression exp, SelectTableInfoType joinType)
 | 
			
		||||
        {
 | 
			
		||||
            _commonExpression.ExpressionJoinLambda(_tables, joinType, exp, null, _whereCascadeExpression);
 | 
			
		||||
            return this as TSelect;
 | 
			
		||||
@@ -1109,7 +1112,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
        protected TSelect InternalOrderBy(Expression column) => this.OrderBy(_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null));
 | 
			
		||||
        protected TSelect InternalOrderByDescending(Expression column) => this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null)} DESC");
 | 
			
		||||
 | 
			
		||||
        protected List<TReturn> InternalToList<TReturn>(Expression select) => this.ToListMapReader<TReturn>(this.GetExpressionField(select));
 | 
			
		||||
        public List<TReturn> InternalToList<TReturn>(Expression select) => this.ToListMapReader<TReturn>(this.GetExpressionField(select));
 | 
			
		||||
        protected string InternalToSql<TReturn>(Expression select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
 | 
			
		||||
        {
 | 
			
		||||
            var af = this.GetExpressionField(select, fieldAlias);
 | 
			
		||||
@@ -1151,7 +1154,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
            return this.ToListMapReader<TReturn>(new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null)).FirstOrDefault();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected TSelect InternalWhere(Expression exp) => exp == null ? this as TSelect : this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp, null, _whereCascadeExpression, _params));
 | 
			
		||||
        public TSelect InternalWhere(Expression exp) => exp == null ? this as TSelect : this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp, null, _whereCascadeExpression, _params));
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
#if net40
 | 
			
		||||
 
 | 
			
		||||
@@ -111,15 +111,15 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
            return this.InternalAvg(column?.Body);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public abstract ISelect<T1, T2> From<T2>(Expression<Func<ISelectFromExpression<T1>, T2, ISelectFromExpression<T1>>> exp) where T2 : class;// { this.InternalFrom(exp); var ret = new Select3Provider<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
			
		||||
        public abstract ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class;// { this.InternalFrom(exp); var ret = new Select3Provider<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class;// { this.InternalFrom(exp); var ret = new Select4Provider<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class;// { this.InternalFrom(exp); var ret = new Select5Provider<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class;// { this.InternalFrom(exp); var ret = new Select6Provider<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class;// { this.InternalFrom(exp); var ret = new Select7Provider<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class;// { this.InternalFrom(exp); var ret = new Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class;// { this.InternalFrom(exp); var ret = new Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class;// { this.InternalFrom(exp); var ret = new Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
			
		||||
        public abstract ISelect<T1, T2> From<T2>(Expression<Func<ISelectFromExpression<T1>, T2, ISelectFromExpression<T1>>> exp) where T2 : class;
 | 
			
		||||
        public abstract ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class;
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class;
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class;
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class;
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class;
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class;
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class;
 | 
			
		||||
        public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class;
 | 
			
		||||
 | 
			
		||||
        public ISelectGrouping<TKey, T1> GroupBy<TKey>(Expression<Func<T1, TKey>> columns)
 | 
			
		||||
        {
 | 
			
		||||
@@ -132,41 +132,48 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
        {
 | 
			
		||||
            if (column == null) return default(TMember);
 | 
			
		||||
            _tables[0].Parameter = column.Parameters[0];
 | 
			
		||||
            return this.InternalMax<TMember>(column?.Body);
 | 
			
		||||
            return this.InternalMax<TMember>(column.Body);
 | 
			
		||||
        }
 | 
			
		||||
        public TMember Min<TMember>(Expression<Func<T1, TMember>> column)
 | 
			
		||||
        {
 | 
			
		||||
            if (column == null) return default(TMember);
 | 
			
		||||
            _tables[0].Parameter = column.Parameters[0];
 | 
			
		||||
            return this.InternalMin<TMember>(column?.Body);
 | 
			
		||||
            return this.InternalMin<TMember>(column.Body);
 | 
			
		||||
        }
 | 
			
		||||
        public void OrderByReflection(LambdaExpression column, bool isDescending)
 | 
			
		||||
        {
 | 
			
		||||
            if (column == null) return;
 | 
			
		||||
            _tables[0].Parameter = column.Parameters[0];
 | 
			
		||||
            if (isDescending) this.InternalOrderByDescending(column.Body);
 | 
			
		||||
            else this.InternalOrderBy(column.Body);
 | 
			
		||||
        }
 | 
			
		||||
        public ISelect<T1> OrderBy<TMember>(Expression<Func<T1, TMember>> column) => this.OrderBy(true, column);
 | 
			
		||||
        public ISelect<T1> OrderBy<TMember>(bool condition, Expression<Func<T1, TMember>> column)
 | 
			
		||||
        {
 | 
			
		||||
            if (condition == false || column == null) return this;
 | 
			
		||||
            _tables[0].Parameter = column.Parameters[0];
 | 
			
		||||
            return this.InternalOrderBy(column?.Body);
 | 
			
		||||
            return this.InternalOrderBy(column.Body);
 | 
			
		||||
        }
 | 
			
		||||
        public ISelect<T1> OrderByDescending<TMember>(Expression<Func<T1, TMember>> column) => this.OrderByDescending(true, column);
 | 
			
		||||
        public ISelect<T1> OrderByDescending<TMember>(bool condition, Expression<Func<T1, TMember>> column)
 | 
			
		||||
        {
 | 
			
		||||
            if (condition == false || column == null) return this;
 | 
			
		||||
            _tables[0].Parameter = column.Parameters[0];
 | 
			
		||||
            return this.InternalOrderByDescending(column?.Body);
 | 
			
		||||
            return this.InternalOrderByDescending(column.Body);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public decimal Sum<TMember>(Expression<Func<T1, TMember>> column)
 | 
			
		||||
        {
 | 
			
		||||
            if (column == null) return default(decimal);
 | 
			
		||||
            _tables[0].Parameter = column.Parameters[0];
 | 
			
		||||
            return this.InternalSum(column?.Body);
 | 
			
		||||
            return this.InternalSum(column.Body);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<TReturn> ToList<TReturn>(Expression<Func<T1, TReturn>> select)
 | 
			
		||||
        {
 | 
			
		||||
            if (select == null) return this.InternalToList<TReturn>(select?.Body);
 | 
			
		||||
            _tables[0].Parameter = select.Parameters[0];
 | 
			
		||||
            return this.InternalToList<TReturn>(select?.Body);
 | 
			
		||||
            return this.InternalToList<TReturn>(select.Body);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public List<TDto> ToList<TDto>() => ToList(GetToListDtoSelector<TDto>());
 | 
			
		||||
@@ -177,89 +184,6 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
                _tables[0].Parameter ?? Expression.Parameter(typeof(T1), "a"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #region linq to sql
 | 
			
		||||
        public ISelect<TReturn> Select<TReturn>(Expression<Func<T1, TReturn>> select) where TReturn : class
 | 
			
		||||
        {
 | 
			
		||||
            if (typeof(TReturn) == typeof(T1)) return this as ISelect<TReturn>;
 | 
			
		||||
            _tables[0].Parameter = select.Parameters[0];
 | 
			
		||||
            _selectExpression = select.Body;
 | 
			
		||||
            if (_orm.CodeFirst.IsAutoSyncStructure)
 | 
			
		||||
                (_orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TReturn)); //._dicSyced.TryAdd(typeof(TReturn), true);
 | 
			
		||||
            var ret = _orm.Select<TReturn>();
 | 
			
		||||
            Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
        public ISelect<TResult> Join<TInner, TKey, TResult>(ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, TInner, TResult>> resultSelector) where TInner : class where TResult : class
 | 
			
		||||
        {
 | 
			
		||||
            _tables[0].Parameter = resultSelector.Parameters[0];
 | 
			
		||||
            _commonExpression.ExpressionLambdaToSql(outerKeySelector, new CommonExpression.ExpTSC { _tables = _tables });
 | 
			
		||||
            this.InternalJoin(Expression.Lambda<Func<T1, TInner, bool>>(
 | 
			
		||||
                Expression.Equal(outerKeySelector.Body, innerKeySelector.Body),
 | 
			
		||||
                new[] { outerKeySelector.Parameters[0], innerKeySelector.Parameters[0] }
 | 
			
		||||
            ), SelectTableInfoType.InnerJoin);
 | 
			
		||||
            if (typeof(TResult) == typeof(T1)) return this as ISelect<TResult>;
 | 
			
		||||
            _selectExpression = resultSelector.Body;
 | 
			
		||||
            if (_orm.CodeFirst.IsAutoSyncStructure)
 | 
			
		||||
                (_orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
 | 
			
		||||
            var ret = _orm.Select<TResult>() as Select1Provider<TResult>;
 | 
			
		||||
            Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
        public ISelect<TResult> GroupJoin<TInner, TKey, TResult>(ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, ISelect<TInner>, TResult>> resultSelector) where TInner : class where TResult : class
 | 
			
		||||
        {
 | 
			
		||||
            _tables[0].Parameter = resultSelector.Parameters[0];
 | 
			
		||||
            _commonExpression.ExpressionLambdaToSql(outerKeySelector, new CommonExpression.ExpTSC { _tables = _tables });
 | 
			
		||||
            this.InternalJoin(Expression.Lambda<Func<T1, TInner, bool>>(
 | 
			
		||||
                Expression.Equal(outerKeySelector.Body, innerKeySelector.Body),
 | 
			
		||||
                new[] { outerKeySelector.Parameters[0], innerKeySelector.Parameters[0] }
 | 
			
		||||
            ), SelectTableInfoType.InnerJoin);
 | 
			
		||||
            if (typeof(TResult) == typeof(T1)) return this as ISelect<TResult>;
 | 
			
		||||
            _selectExpression = resultSelector.Body;
 | 
			
		||||
            if (_orm.CodeFirst.IsAutoSyncStructure)
 | 
			
		||||
                (_orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
 | 
			
		||||
            var ret = _orm.Select<TResult>() as Select1Provider<TResult>;
 | 
			
		||||
            Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
        public ISelect<TResult> SelectMany<TCollection, TResult>(Expression<Func<T1, ISelect<TCollection>>> collectionSelector, Expression<Func<T1, TCollection, TResult>> resultSelector) where TCollection : class where TResult : class
 | 
			
		||||
        {
 | 
			
		||||
            SelectTableInfo find = null;
 | 
			
		||||
            if (collectionSelector.Body.NodeType == ExpressionType.Call)
 | 
			
		||||
            {
 | 
			
		||||
                var callExp = collectionSelector.Body as MethodCallExpression;
 | 
			
		||||
                if (callExp.Method.Name == "DefaultIfEmpty" && callExp.Object.Type.GetGenericArguments().Any())
 | 
			
		||||
                {
 | 
			
		||||
                    find = _tables.Where((a, idx) => idx > 0 && a.Type == SelectTableInfoType.InnerJoin && a.Table.Type == callExp.Object.Type.GetGenericArguments()[0]).LastOrDefault();
 | 
			
		||||
                    if (find != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (!string.IsNullOrEmpty(find.On)) find.On = Regex.Replace(find.On, $@"\b{find.Alias}\.", $"{resultSelector.Parameters[1].Name}.");
 | 
			
		||||
                        if (!string.IsNullOrEmpty(find.NavigateCondition)) find.NavigateCondition = Regex.Replace(find.NavigateCondition, $@"\b{find.Alias}\.", $"{resultSelector.Parameters[1].Name}.");
 | 
			
		||||
                        find.Type = SelectTableInfoType.LeftJoin;
 | 
			
		||||
                        find.Alias = resultSelector.Parameters[1].Name;
 | 
			
		||||
                        find.Parameter = resultSelector.Parameters[1];
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (find == null)
 | 
			
		||||
            {
 | 
			
		||||
                var tb = _commonUtils.GetTableByEntity(typeof(TCollection));
 | 
			
		||||
                if (tb == null) throw new Exception($"SelectMany 错误的类型:{typeof(TCollection).FullName}");
 | 
			
		||||
                _tables.Add(new SelectTableInfo { Alias = resultSelector.Parameters[1].Name, AliasInit = resultSelector.Parameters[1].Name, Parameter = resultSelector.Parameters[1], Table = tb, Type = SelectTableInfoType.From });
 | 
			
		||||
            }
 | 
			
		||||
            if (typeof(TResult) == typeof(T1)) return this as ISelect<TResult>;
 | 
			
		||||
            _selectExpression = resultSelector.Body;
 | 
			
		||||
            if (_orm.CodeFirst.IsAutoSyncStructure)
 | 
			
		||||
                (_orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
 | 
			
		||||
            var ret = _orm.Select<TResult>() as Select1Provider<TResult>;
 | 
			
		||||
            Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
        public ISelect<T1> DefaultIfEmpty()
 | 
			
		||||
        {
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        public DataTable ToDataTable<TReturn>(Expression<Func<T1, TReturn>> select)
 | 
			
		||||
        {
 | 
			
		||||
            if (select == null) return this.InternalToDataTable(select?.Body);
 | 
			
		||||
@@ -1083,8 +1007,6 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
            _trackToList?.Invoke(list);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IQueryable<T1> AsQueryable() => new QueryableProvider<T1>(this);
 | 
			
		||||
 | 
			
		||||
#if net40
 | 
			
		||||
#else
 | 
			
		||||
        async internal Task SetListAsync(IEnumerable<T1> list)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
using FreeSql.Internal.Model;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
@@ -9,14 +10,15 @@ using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
{
 | 
			
		||||
    public class SelectGroupingProvider<TKey, TValue> : ISelectGrouping<TKey, TValue>
 | 
			
		||||
    public class SelectGroupingProvider
 | 
			
		||||
    {
 | 
			
		||||
        internal IFreeSql _orm;
 | 
			
		||||
        internal object _select;
 | 
			
		||||
        internal ReadAnonymousTypeInfo _map;
 | 
			
		||||
        internal string _field;
 | 
			
		||||
        internal CommonExpression _comonExp;
 | 
			
		||||
        internal List<SelectTableInfo> _tables;
 | 
			
		||||
        public IFreeSql _orm;
 | 
			
		||||
        public object _select;
 | 
			
		||||
        public ReadAnonymousTypeInfo _map;
 | 
			
		||||
        public string _field;
 | 
			
		||||
        public CommonExpression _comonExp;
 | 
			
		||||
        public List<SelectTableInfo> _tables;
 | 
			
		||||
 | 
			
		||||
        public SelectGroupingProvider(IFreeSql orm, object select, ReadAnonymousTypeInfo map, string field, CommonExpression comonExp, List<SelectTableInfo> tables)
 | 
			
		||||
        {
 | 
			
		||||
            _orm = orm;
 | 
			
		||||
@@ -27,7 +29,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
            _tables = tables;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        string getSelectGroupingMapString(Expression[] members)
 | 
			
		||||
        public string getSelectGroupingMapString(Expression[] members)
 | 
			
		||||
        {
 | 
			
		||||
            if (members.Any() == false) return _map.DbField;
 | 
			
		||||
            var parentName = ((members.FirstOrDefault() as MemberExpression)?.Expression as MemberExpression)?.Member.Name;
 | 
			
		||||
@@ -85,59 +87,45 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ISelectGrouping<TKey, TValue> Having(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, bool>> exp)
 | 
			
		||||
        public void InternalHaving(Expression exp)
 | 
			
		||||
        {
 | 
			
		||||
            var sql = _comonExp.ExpressionWhereLambda(null, exp, getSelectGroupingMapString, null, null);
 | 
			
		||||
            var method = _select.GetType().GetMethod("Having", new[] { typeof(string), typeof(object) });
 | 
			
		||||
            method.Invoke(_select, new object[] { sql, null });
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ISelectGrouping<TKey, TValue> OrderBy<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column)
 | 
			
		||||
        public void InternalOrderBy(Expression exp, bool isDescending)
 | 
			
		||||
        {
 | 
			
		||||
            var sql = _comonExp.ExpressionWhereLambda(null, column, getSelectGroupingMapString, null, null);
 | 
			
		||||
            var sql = _comonExp.ExpressionWhereLambda(null, exp, getSelectGroupingMapString, null, null);
 | 
			
		||||
            var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) });
 | 
			
		||||
            method.Invoke(_select, new object[] { sql, null });
 | 
			
		||||
            return this;
 | 
			
		||||
            method.Invoke(_select, new object[] { isDescending ? $"{sql} DESC" : sql, null });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ISelectGrouping<TKey, TValue> OrderByDescending<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column)
 | 
			
		||||
        {
 | 
			
		||||
            var sql = _comonExp.ExpressionWhereLambda(null, column, getSelectGroupingMapString, null, null);
 | 
			
		||||
            var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) });
 | 
			
		||||
            method.Invoke(_select, new object[] { $"{sql} DESC", null });
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<TReturn> Select<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => ToList(select);
 | 
			
		||||
        public List<TReturn> ToList<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select)
 | 
			
		||||
        public object InternalToList(Expression select, Type elementType, bool isAsync)
 | 
			
		||||
        {
 | 
			
		||||
            var map = new ReadAnonymousTypeInfo();
 | 
			
		||||
            var field = new StringBuilder();
 | 
			
		||||
            var index = 0;
 | 
			
		||||
 | 
			
		||||
            _comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString, null, false);
 | 
			
		||||
            if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn);
 | 
			
		||||
            var method = _select.GetType().GetMethod("ToListMapReader", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
			
		||||
            method = method.MakeGenericMethod(typeof(TReturn));
 | 
			
		||||
            return method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }) as List<TReturn>;
 | 
			
		||||
            if (map.Childs.Any() == false && map.MapType == null) map.MapType = elementType;
 | 
			
		||||
            var method = _select.GetType().GetMethod(isAsync ? "ToListMapReaderAsync" : "ToListMapReader", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
			
		||||
            method = method.MakeGenericMethod(elementType);
 | 
			
		||||
            return method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) });
 | 
			
		||||
        }
 | 
			
		||||
        public Dictionary<TKey, TElement> ToDictionary<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector)
 | 
			
		||||
        public IEnumerable<KeyValuePair<object, object>> InternalToKeyValuePairs(Expression elementSelector, Type elementType)
 | 
			
		||||
        {
 | 
			
		||||
            var map = new ReadAnonymousTypeInfo();
 | 
			
		||||
            var field = new StringBuilder();
 | 
			
		||||
            var index = 0;
 | 
			
		||||
 | 
			
		||||
            _comonExp.ReadAnonymousField(null, field, map, ref index, elementSelector, getSelectGroupingMapString, null, false);
 | 
			
		||||
            if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TElement);
 | 
			
		||||
            if (map.Childs.Any() == false && map.MapType == null) map.MapType = elementType;
 | 
			
		||||
            var method = _select.GetType().GetMethod("ToListMapReaderPrivate", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
			
		||||
            method = method.MakeGenericMethod(typeof(TElement));
 | 
			
		||||
            method = method.MakeGenericMethod(elementType);
 | 
			
		||||
            var otherAf = new ReadAnonymousTypeOtherInfo(_field, _map, new List<object>());
 | 
			
		||||
            var values = method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null), new[] { otherAf } }) as List<TElement>;
 | 
			
		||||
            return otherAf.retlist.Select((a, b) => new KeyValuePair<TKey, TElement>((TKey)a, values[b])).ToDictionary(a => a.Key, a => a.Value);
 | 
			
		||||
            var values = method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null), new[] { otherAf } }) as IList;
 | 
			
		||||
            return otherAf.retlist.Select((a, b) => new KeyValuePair<object, object>(a, values[b]));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string ToSql<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
 | 
			
		||||
        public string InternalToSql(Expression select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
 | 
			
		||||
        {
 | 
			
		||||
            var map = new ReadAnonymousTypeInfo();
 | 
			
		||||
            var field = new StringBuilder();
 | 
			
		||||
@@ -147,6 +135,14 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
            var method = _select.GetType().GetMethod("ToSql", new[] { typeof(string) });
 | 
			
		||||
            return method.Invoke(_select, new object[] { field.Length > 0 ? field.Remove(0, 2).ToString() : null }) as string;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class SelectGroupingProvider<TKey, TValue> : SelectGroupingProvider, ISelectGrouping<TKey, TValue>
 | 
			
		||||
    {
 | 
			
		||||
        public SelectGroupingProvider(IFreeSql orm, object select, ReadAnonymousTypeInfo map, string field, CommonExpression comonExp, List<SelectTableInfo> tables)
 | 
			
		||||
            :base(orm, select, map, field, comonExp, tables) { }
 | 
			
		||||
 | 
			
		||||
        public string ToSql<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex) => InternalToSql(select, fieldAlias);
 | 
			
		||||
        public string ToSql(string field)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrEmpty(field))
 | 
			
		||||
@@ -163,7 +159,6 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
        public ISelectGrouping<TKey, TValue> Offset(int offset) => this.Skip(offset);
 | 
			
		||||
 | 
			
		||||
        public ISelectGrouping<TKey, TValue> Limit(int limit)
 | 
			
		||||
        {
 | 
			
		||||
            var method = _select.GetType().GetMethod("Limit", new[] { typeof(int) });
 | 
			
		||||
@@ -171,7 +166,6 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
        public ISelectGrouping<TKey, TValue> Take(int limit) => this.Limit(limit);
 | 
			
		||||
 | 
			
		||||
        public ISelectGrouping<TKey, TValue> Page(int pageNumber, int pageSize)
 | 
			
		||||
        {
 | 
			
		||||
            var method = _select.GetType().GetMethod("Page", new[] { typeof(int), typeof(int) });
 | 
			
		||||
@@ -186,22 +180,31 @@ namespace FreeSql.Internal.CommonProvider
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ISelectGrouping<TKey, TValue> Having(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, bool>> exp)
 | 
			
		||||
        {
 | 
			
		||||
            InternalHaving(exp);
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
        public ISelectGrouping<TKey, TValue> OrderBy<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column)
 | 
			
		||||
        {
 | 
			
		||||
            InternalOrderBy(column, false);
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
        public ISelectGrouping<TKey, TValue> OrderByDescending<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column)
 | 
			
		||||
        {
 | 
			
		||||
            InternalOrderBy(column, true);
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<TReturn> Select<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => ToList(select);
 | 
			
		||||
        public List<TReturn> ToList<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => InternalToList(select, typeof(TReturn), false) as List<TReturn>;
 | 
			
		||||
        public Dictionary<TKey, TElement> ToDictionary<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector) => InternalToKeyValuePairs(elementSelector, typeof(TElement)).ToDictionary(a => (TKey)a.Key, a => (TElement)a.Value);
 | 
			
		||||
 | 
			
		||||
#if net40
 | 
			
		||||
#else
 | 
			
		||||
        async public Task<long> CountAsync() => long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync($"select count(1) from ({this.ToSql($"1{_comonExp._common.FieldAsAlias("as1")}")}) fta")), out var trylng) ? trylng : default(long);
 | 
			
		||||
 | 
			
		||||
        public Task<List<TReturn>> ToListAsync<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select)
 | 
			
		||||
        {
 | 
			
		||||
            var map = new ReadAnonymousTypeInfo();
 | 
			
		||||
            var field = new StringBuilder();
 | 
			
		||||
            var index = 0;
 | 
			
		||||
 | 
			
		||||
            _comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString, null, false);
 | 
			
		||||
            if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn);
 | 
			
		||||
            var method = _select.GetType().GetMethod("ToListMapReaderAsync", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
			
		||||
            method = method.MakeGenericMethod(typeof(TReturn));
 | 
			
		||||
            return method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }) as Task<List<TReturn>>;
 | 
			
		||||
        }
 | 
			
		||||
        public Task<List<TReturn>> ToListAsync<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => InternalToList(select, typeof(TReturn), true) as Task<List<TReturn>>;
 | 
			
		||||
        async public Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector)
 | 
			
		||||
        {
 | 
			
		||||
            var map = new ReadAnonymousTypeInfo();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user