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 { Expression _expression; IQueryProvider _provider; internal Select1Provider _select; public QueryableProvider(Select1Provider select) { _select = select; _expression = Expression.Constant(this); _provider = new QueryProvider(_select, _expression); } 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() { return (IEnumerator)GetEnumerator(); } public Type ElementType => typeof(QueryableProvider); public Expression Expression => _expression; public IQueryProvider Provider => _provider; } class QueryProvider : IQueryProvider where TSource : class { Select1Provider _select; Expression _oldExpression; public QueryProvider(Select1Provider select, Expression oldExpression) { _select = select; _oldExpression = oldExpression; } public IQueryable CreateQuery(Expression expression) { ExecuteExp(expression, null, false); if (typeof(TElement) != typeof(TCurrent)) return new QueryableProvider(expression, new QueryProvider(_select, expression), _select); _oldExpression = expression; return new QueryableProvider(expression, this, _select); } public IQueryable CreateQuery(Expression expression) => throw new NotImplementedException(); public TResult Execute(Expression expression) { return (TResult)ExecuteExp(expression, typeof(TResult), _oldExpression == expression); } public object Execute(Expression expression) => throw new NotImplementedException(); public object ExecuteExp(Expression expression, Type tresult, bool isProcessed) { var callExp = expression as MethodCallExpression; var isfirst = false; if (callExp != null && isProcessed == false) { object throwCallExp(string message) => throw new Exception($"解析失败 {callExp.Method.Name} {message},提示:可以使用扩展方法 IQueryable.RestoreToSelect() 还原为 ISelect 再查询"); if (callExp.Method.DeclaringType != typeof(Queryable)) return throwCallExp($"必须属于 System.Linq.Queryable"); object tplMaxMinAvgSum(string method) { if (callExp.Arguments.Count == 2) { var avgParam = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression; return Utils.GetDataReaderValue(tresult, _select.GetType().GetMethod(method).MakeGenericMethod(avgParam.ReturnType).Invoke(_select, new object[] { avgParam })); } return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法"); } object 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 tresult.CreateInstanceGetDefaultValue(); } return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法"); } switch (callExp.Method.Name) { case "Any": if (callExp.Arguments.Count == 2) _select.InternalWhere(callExp.Arguments[1]); return _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(CoreStrings.Not_Support); case "Contains": if (callExp.Arguments.Count == 2) { var dywhere = callExp.Arguments[1].GetConstExprValue(); if (dywhere == null) return throwCallExp($" 参数值不能为 null"); _select.WhereDynamic(dywhere); return _select.Any(); } return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法"); case "Count": if (callExp.Arguments.Count == 2) _select.InternalWhere(callExp.Arguments[1]); return Utils.GetDataReaderValue(tresult, _select.Count()); case "Distinct": if (callExp.Arguments.Count == 1) { _select.Distinct(); break; } return throwCallExp(CoreStrings.Not_Support); 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) { _select.InternalWhere(whereParam); break; } return throwCallExp(CoreStrings.Not_Support); 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 _select.ToList(); return throwCallExp(CoreStrings.Not_Support); case "Select": var selectParam = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression; if (selectParam.Parameters.Count == 1) { _select._selectExpression = selectParam; break; } return throwCallExp(CoreStrings.Not_Support); 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(CoreStrings.Not_Support); case "GroupBy": return throwCallExp(CoreStrings.Not_Support); default: return throwCallExp(CoreStrings.Not_Support); } } if (tresult == null) return null; if (isfirst) { _select.Limit(1); if (_select._selectExpression != null) return _select.InternalToList(_select._selectExpression).FirstOrDefault(); return _select.ToList().FirstOrDefault(); } if (_select._selectExpression != null) return _select.InternalToList(_select._selectExpression); return _select.ToList(); } } }