using FreeSql.Internal; using FreeSql.Internal.CommonProvider; using FreeSql.Internal.Model; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; namespace FreeSql.Extensions.Linq { class QueryableProvider : IQueryable, IOrderedQueryable where TSource : class { private Expression _expression; private IQueryProvider _provider; private Select1Provider _select; public QueryableProvider(Select1Provider select) { _select = select; _expression = Expression.Constant(this); _provider = new QueryProvider(_select); } public QueryableProvider(Expression expression, IQueryProvider provider, Select1Provider select) { _select = select; _expression = expression; _provider = provider; } public IEnumerator GetEnumerator() { var result = _provider.Execute>(_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); public Expression Expression => _expression; public IQueryProvider Provider => _provider; } class QueryProvider : IQueryProvider where TSource : class { private Select1Provider _select; public QueryProvider(Select1Provider select) { _select = select; } public IQueryable CreateQuery(Expression expression) { if (typeof(TElement) != typeof(TCurrent)) return new QueryableProvider(expression, new QueryProvider(_select), _select); return new QueryableProvider(expression, this, _select); } public IQueryable CreateQuery(Expression expression) => throw new NotImplementedException(); public TResult Execute(Expression expression) { var stackCallExps = new Stack(); var callExp = expression as MethodCallExpression; while(callExp != null) { stackCallExps.Push(callExp); callExp = callExp?.Arguments.FirstOrDefault() as MethodCallExpression; } SelectGroupingProvider groupBy = null; var isfirst = false; while (stackCallExps.Any()) { callExp = stackCallExps.Pop(); TResult throwCallExp(string message) => throw new Exception($"FreeSql Queryable 解析出错,执行的方法 {callExp.Method.Name} {message}"); if (callExp.Method.DeclaringType != typeof(Queryable)) return throwCallExp($"必须属于 System.Linq.Queryable"); TResult tplMaxMinAvgSum(string method) { if (callExp.Arguments.Count == 2) { var avgParam = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression; return (TResult)Utils.GetDataReaderValue(typeof(TResult), _select.GetType().GetMethod(method).MakeGenericMethod(avgParam.ReturnType).Invoke(_select, new object[] { avgParam })); } return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法"); } TResult tplOrderBy(string method, bool isDescending) { if (callExp.Arguments.Count == 2) { var arg1 = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression; _select.OrderByReflection(arg1, isDescending); return default(TResult); } return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法"); } switch (callExp.Method.Name) { case "Any": if (callExp.Arguments.Count == 2) _select.InternalWhere(callExp.Arguments[1]); return (TResult)(object)_select.Any(); case "AsQueryable": break; case "Max": return tplMaxMinAvgSum("Max"); case "Min": return tplMaxMinAvgSum("Min"); case "Sum": return tplMaxMinAvgSum("Sum"); case "Average": return tplMaxMinAvgSum("Avg"); case "Concat": return throwCallExp(" 不支持"); case "Contains": if (callExp.Arguments.Count == 2) { var dywhere = callExp.Arguments[1].GetConstExprValue(); if (dywhere == null) return throwCallExp($" 参数值不能为 null"); _select.WhereDynamic(dywhere); return (TResult)(object)_select.Any(); } return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法"); case "Count": if (callExp.Arguments.Count == 2) _select.InternalWhere(callExp.Arguments[1]); return (TResult)Utils.GetDataReaderValue(typeof(TResult), _select.Count()); case "Distinct": if (callExp.Arguments.Count == 1) { _select.Distinct(); break; } return throwCallExp(" 不支持"); case "ElementAt": case "ElementAtOrDefault": _select.Offset((int)callExp.Arguments[1].GetConstExprValue()); _select.Limit(1); isfirst = true; break; case "First": case "FirstOrDefault": case "Single": case "SingleOrDefault": if (callExp.Arguments.Count == 2) _select.InternalWhere(callExp.Arguments[1]); _select.Limit(1); isfirst = true; break; case "OrderBy": tplOrderBy("OrderByReflection", false); break; case "OrderByDescending": tplOrderBy("OrderByReflection", true); break; case "ThenBy": tplOrderBy("OrderByReflection", false); break; case "ThenByDescending": tplOrderBy("OrderByReflection", true); break; case "Where": var whereParam = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression; if (whereParam.Parameters.Count == 1) { if (groupBy != null) groupBy.InternalHaving(whereParam); else _select.InternalWhere(whereParam); break; } return throwCallExp(" 不支持"); case "Skip": _select.Offset((int)callExp.Arguments[1].GetConstExprValue()); break; case "Take": _select.Limit((int)callExp.Arguments[1].GetConstExprValue()); break; case "ToList": if (callExp.Arguments.Count == 1) return (TResult)(object)_select.ToList(); return throwCallExp(" 不支持"); case "Select": var selectParam = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression; if (selectParam.Parameters.Count == 1) { _select._selectExpression = selectParam; break; } return throwCallExp(" 不支持"); case "Join": if (callExp.Arguments.Count == 5) { var arg2 = (callExp.Arguments[2] as UnaryExpression)?.Operand as LambdaExpression; var arg3 = (callExp.Arguments[3] as UnaryExpression)?.Operand as LambdaExpression; var arg4 = (callExp.Arguments[4] as UnaryExpression)?.Operand as LambdaExpression; FreeSqlExtensionsLinqSql.InternalJoin2(_select, arg2, arg3, arg4); _select._selectExpression = arg4.Body; break; } return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法"); case "GroupJoin": if (callExp.Arguments.Count == 5) { var arg2 = (callExp.Arguments[2] as UnaryExpression)?.Operand as LambdaExpression; var arg3 = (callExp.Arguments[3] as UnaryExpression)?.Operand as LambdaExpression; var arg4 = (callExp.Arguments[4] as UnaryExpression)?.Operand as LambdaExpression; FreeSqlExtensionsLinqSql.InternalJoin2(_select, arg2, arg3, arg4); _select._selectExpression = arg4.Body; break; } return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法"); case "SelectMany": if (callExp.Arguments.Count == 3) { var arg1 = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression; var arg2 = (callExp.Arguments[2] as UnaryExpression)?.Operand as LambdaExpression; FreeSqlExtensionsLinqSql.InternalSelectMany2(_select, arg1, arg2); _select._selectExpression = arg2.Body; break; } return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法"); case "DefaultIfEmpty": break; case "Last": case "LastOrDefault": return throwCallExp(" 不支持"); case "GroupBy": return throwCallExp(" 不支持"); if (callExp.Arguments.Count == 2) //TODO: 待实现 { var arg1 = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression; var map = new ReadAnonymousTypeInfo(); var field = new StringBuilder(); var index = -10000; //临时规则,不返回 as1 _select._commonExpression.ReadAnonymousField(_select._tables, field, map, ref index, arg1, null, _select._whereCascadeExpression, false); //不走 DTO 映射 var sql = field.ToString(); _select.GroupBy(sql.Length > 0 ? sql.Substring(2) : null); groupBy = new SelectGroupingProvider(_select._orm, _select, map, sql, _select._commonExpression, _select._tables); break; } return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法"); default: return throwCallExp(" 不支持"); } } if (isfirst) { _select.Limit(1); if (_select._selectExpression != null) return (TResult)(object)_select.InternalToList(_select._selectExpression).FirstOrDefault(); return (TResult)(object)_select.ToList().FirstOrDefault(); } if (_select._selectExpression != null) return (TResult)(object)_select.InternalToList(_select._selectExpression); return (TResult)(object)_select.ToList(); } public object Execute(Expression expression) => throw new NotImplementedException(); } }