using FreeSql; using FreeSql.Extensions.Linq; using FreeSql.Internal; using FreeSql.Internal.CommonProvider; using FreeSql.Internal.Model; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Text.RegularExpressions; public static class FreeSqlExtensionsLinqSql { /// /// 将 ISelect<T1> 转换为 IQueryable<T1> /// 用于扩展如:abp IRepository GetAll() 接口方法需要返回 IQueryable 对象 /// 提示:IQueryable 方法污染严重,查询功能的实现也不理想,应尽量避免此转换 /// IQueryable<T1> 扩展方法 RestoreToSelect() 可以还原为 ISelect<T1> /// /// public static IQueryable AsQueryable(this ISelect that) where T1 : class { return new QueryableProvider(that as Select1Provider); } /// /// 将 IQueryable<T1> 转换为 ISelect<T1> /// 前提:IQueryable 必须由 FreeSql.Extensions.Linq.QueryableProvider 实现 /// /// /// /// public static ISelect RestoreToSelect(this IQueryable that) where T1 : class { var queryable = that as QueryableProvider ?? throw new Exception(CoreStrings.S_CannotBeConverted_To_ISelect(typeof(T1).Name)); return queryable._select; } /// /// 【linq to sql】专用扩展方法,不建议直接使用 /// public static ISelect Select(this ISelect that, Expression> select) { var s1p = that as Select1Provider; if (typeof(TReturn) == typeof(T1)) return that as ISelect; s1p._tables[0].Parameter = select.Parameters[0]; s1p._selectExpression = select.Body; if (s1p._orm.CodeFirst.IsAutoSyncStructure) (s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TReturn)); //._dicSyced.TryAdd(typeof(TReturn), true); var ret = (s1p._orm as BaseDbProvider).CreateSelectProvider(null) as Select1Provider; Select0Provider.CopyData(s1p, ret, null); return ret; } /// /// 【linq to sql】专用扩展方法,不建议直接使用 /// public static ISelect Join(this ISelect that, ISelect inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression> resultSelector) where T1 : class where TInner : class where TResult : class { var s1p = that as Select1Provider; InternalJoin2(s1p, outerKeySelector, innerKeySelector, resultSelector); if (typeof(TResult) == typeof(T1)) return that as ISelect; s1p._selectExpression = resultSelector.Body; if (s1p._orm.CodeFirst.IsAutoSyncStructure) (s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true); var ret = s1p._orm.Select() as Select1Provider; Select0Provider.CopyData(s1p, ret, null); return ret; } internal static void InternalJoin2(Select1Provider s1p, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector, LambdaExpression resultSelector) where T1 : class { s1p._tables[0].Parameter = resultSelector.Parameters[0]; s1p._commonExpression.ExpressionLambdaToSql(outerKeySelector, new CommonExpression.ExpTSC { _tables = s1p._tables, _tableRule = s1p._tableRule }); s1p.InternalJoin(Expression.Lambda(typeof(Func<,,>).MakeGenericType(typeof(T1), innerKeySelector.Parameters[0].Type, typeof(bool)), Expression.Equal(outerKeySelector.Body, innerKeySelector.Body), new[] { outerKeySelector.Parameters[0], innerKeySelector.Parameters[0] } ), SelectTableInfoType.InnerJoin); } /// /// 【linq to sql】专用扩展方法,不建议直接使用 /// public static ISelect GroupJoin(this ISelect that, ISelect inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression, TResult>> resultSelector) where T1 : class where TInner : class where TResult : class { var s1p = that as Select1Provider; InternalJoin2(s1p, outerKeySelector, innerKeySelector, resultSelector); if (typeof(TResult) == typeof(T1)) return that as ISelect; s1p._selectExpression = resultSelector.Body; if (s1p._orm.CodeFirst.IsAutoSyncStructure) (s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true); var ret = s1p._orm.Select() as Select1Provider; Select0Provider.CopyData(s1p, ret, null); return ret; } /// /// 【linq to sql】专用扩展方法,不建议直接使用 /// public static ISelect SelectMany(this ISelect that, Expression>> collectionSelector, Expression> resultSelector) where T1 : class where TCollection : class where TResult : class { var s1p = that as Select1Provider; InternalSelectMany2(s1p, collectionSelector, resultSelector); if (typeof(TResult) == typeof(T1)) return that as ISelect; s1p._selectExpression = resultSelector.Body; if (s1p._orm.CodeFirst.IsAutoSyncStructure) (s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true); var ret = s1p._orm.Select() as Select1Provider; Select0Provider.CopyData(s1p, ret, null); return ret; } internal static void InternalSelectMany2(Select1Provider s1p, LambdaExpression collectionSelector, LambdaExpression resultSelector) where T1 : class { SelectTableInfo find = null; if (collectionSelector.Body.NodeType == ExpressionType.Call) { var callExp = collectionSelector.Body as MethodCallExpression; if (callExp.Method.Name == "DefaultIfEmpty" && callExp.Method.GetGenericArguments().Any()) { find = s1p._tables.Where((a, idx) => idx > 0 && a.Type == SelectTableInfoType.InnerJoin && a.Table.Type == callExp.Method.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 = s1p._commonUtils.GetTableByEntity(resultSelector.Parameters[1].Type); if (tb == null) throw new Exception($"SelectMany 错误的类型:{resultSelector.Parameters[1].Type.FullName}"); s1p._tables.Add(new SelectTableInfo { Alias = resultSelector.Parameters[1].Name, AliasInit = resultSelector.Parameters[1].Name, Parameter = resultSelector.Parameters[1], Table = tb, Type = SelectTableInfoType.From }); } } /// /// 【linq to sql】专用扩展方法,不建议直接使用 /// public static ISelect DefaultIfEmpty(this ISelect that) where T1 : class { return that; } /// /// 【linq to sql】专用扩展方法,不建议直接使用 /// public static ISelect ThenBy(this ISelect that, Expression> column) where T1 : class => that.OrderBy(column); /// /// 【linq to sql】专用扩展方法,不建议直接使用 /// public static ISelect ThenByDescending(this ISelect that, Expression> column) where T1 : class => that.OrderByDescending(column); }