SqlInfo[] ConvertToIndexInternal(Expression? expression, int level, ConvertFlags flags) { if (IsScalar) { if (Body.NodeType == ExpressionType.Parameter) for (var i = 0; i < Sequence.Length; i++) if (Body == Lambda.Parameters[i]) return Sequence[i].ConvertToIndex(expression, level, flags); if (expression == null) { var key = Tuple.Create((MemberInfo?)null, flags); if (!_memberIndex.TryGetValue(key, out var idx)) { idx = ConvertToSql(null, 0, flags); foreach (var info in idx) SetInfo(info, null); _memberIndex.Add(key, idx); } return idx; } switch (flags) { case ConvertFlags.Field : case ConvertFlags.Key : case ConvertFlags.All : return ProcessScalar( expression, level, (ctx, ex, l) => ctx.ConvertToIndex(ex, l, flags), () => GetSequence(expression, level)!.ConvertToIndex(expression, level + 1, flags)); } } else { if (expression == null) { switch (flags) { case ConvertFlags.Field : case ConvertFlags.Key : case ConvertFlags.All : { var p = Expression.Parameter(Body.Type, "p"); var q = from m in Members.Keys where !(m is MethodInfo || EagerLoading.IsDetailsMember(m)) select new SqlData { Sql = ConvertToIndex(Expression.MakeMemberAccess(p, m), 1, flags), Member = m } into mm from m in mm.Sql.Select(s => s.Clone(mm.Member)) select m; return q.ToArray(); } } } switch (flags) { case ConvertFlags.All : case ConvertFlags.Key : case ConvertFlags.Field : { if (level == 0) { var idx = Builder.ConvertExpressions(this, expression!, flags); foreach (var info in idx) SetInfo(info, null); return idx; } var levelExpression = expression!.GetLevelExpression(Builder.MappingSchema, level); switch (levelExpression.NodeType) { case ExpressionType.MemberAccess : { if (levelExpression == expression) { var member = Tuple.Create((MemberInfo?)((MemberExpression)levelExpression).Member, flags); if (!_memberIndex.TryGetValue(member, out var idx)) { idx = ConvertToSql(expression, level, flags); if (flags == ConvertFlags.Field && idx.Length != 1) throw new InvalidOperationException(); foreach (var info in idx) SetInfo(info, member.Item1); _memberIndex.Add(member, idx); } return idx; } return ProcessMemberAccess( expression!, (MemberExpression)levelExpression, level, (n, ctx, ex, l, _) => n == 0 ? GetSequence(expression!, level)!.ConvertToIndex(expression, level + 1, flags) : ctx.ConvertToIndex(ex, l, flags)); } case ExpressionType.Parameter: case ExpressionType.Extension: if (levelExpression != expression) return GetSequence(expression!, level)!.ConvertToIndex(expression, level + 1, flags); break; } break; } } } throw new NotImplementedException(); }
public virtual SqlInfo[] ConvertToSql(Expression? expression, int level, ConvertFlags flags) { if (expression != null && level > 0 && expression.NodeType == ExpressionType.Call) { var e = (MethodCallExpression)expression; if (e.Method.DeclaringType == typeof(Enumerable) && !typeof(IGrouping<,>).IsSameOrParentOf(e.Arguments[0].Type)) { return new[] { new SqlInfo { Sql = Builder.SubQueryToSql(this, e) } }; } } if (IsScalar) { if (expression == null) return Builder.ConvertExpressions(this, Body, flags); switch (flags) { case ConvertFlags.Field : case ConvertFlags.Key : case ConvertFlags.All : { if (Body.NodeType != ExpressionType.Parameter && level == 0) { var levelExpression = expression.GetLevelExpression(Builder.MappingSchema, level); if (levelExpression != expression) if (flags != ConvertFlags.Field && IsExpression(expression, level, RequestFor.Field).Result) flags = ConvertFlags.Field; } return ProcessScalar( expression, level, (ctx, ex, l) => ctx.ConvertToSql(ex, l, flags), () => new[] { new SqlInfo { Sql = Builder.ConvertToSql(this, expression) } }); } } } else { if (expression == null) { if (flags != ConvertFlags.Field) { var q = from m in Members where !(m.Key is MethodInfo || EagerLoading.IsDetailsMember(m.Key)) select ConvertMember(m.Key, m.Value, flags) into mm from m in mm select m; return q.ToArray(); } throw new NotImplementedException(); } switch (flags) { case ConvertFlags.All : case ConvertFlags.Key : case ConvertFlags.Field : { var levelExpression = expression.GetLevelExpression(Builder.MappingSchema, level); levelExpression = levelExpression.Unwrap(); switch (levelExpression.NodeType) { case ExpressionType.MemberAccess : { if (level != 0 && levelExpression == expression) { var member = ((MemberExpression)levelExpression).Member; if (!_sql.TryGetValue(member, out var sql)) { var memberExpression = GetMemberExpression( member, levelExpression == expression, levelExpression.Type, expression); sql = ConvertExpressions(memberExpression, flags) .Select(si => si.Clone(member)).ToArray(); _sql.Add(member, sql); } return sql; } return ProcessMemberAccess( expression, (MemberExpression)levelExpression, level, (n,ctx,ex,l,mex) => { switch (n) { case 0 : var buildExpression = GetExpression(expression, levelExpression, mex); return ConvertExpressions(buildExpression, flags); default: return ctx.ConvertToSql(ex, l, flags); } }); } case ExpressionType.Parameter: if (levelExpression != expression) return GetSequence(expression, level)!.ConvertToSql(expression, level + 1, flags); if (level == 0) return GetSequence(expression, level)!.ConvertToSql(null, 0, flags); break; case ExpressionType.Extension: { if (levelExpression is ContextRefExpression) { if (levelExpression != expression) return GetSequence(expression, level)!.ConvertToSql(expression, level + 1, flags); if (level == 0) return GetSequence(expression, level)!.ConvertToSql(null, 0, flags); } goto default; } default: if (level == 0) return Builder.ConvertExpressions(this, expression, flags); break; } break; } } } throw new NotImplementedException(); }