예제 #1
0
		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
			var query    = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SqlQuery()));
			var except   = query.SqlQuery;

			sequence = new SubQueryContext(sequence);

			var sql = sequence.SqlQuery;

			except.ParentSql = sql;

			if (methodCall.Method.Name == "Except")
				sql.Where.Not.Exists(except);
			else
				sql.Where.Exists(except);

			var keys1 = sequence.ConvertToSql(null, 0, ConvertFlags.Key);
			var keys2 = query.   ConvertToSql(null, 0, ConvertFlags.Key);

			if (keys1.Length != keys2.Length)
				throw new InvalidOperationException();

			for (var i = 0; i < keys1.Length; i++)
			{
				except.Where
					.Expr(keys1[i].Sql)
					.Equal
					.Expr(keys2[i].Sql);
			}

			return sequence;
		}
예제 #2
0
		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

			if (sequence.SqlQuery.Select.TakeValue != null || sequence.SqlQuery.Select.SkipValue != null)
				sequence = new SubQueryContext(sequence);

			var lambda  = (LambdaExpression)methodCall.Arguments[1].Unwrap();
			var sparent = sequence.Parent;
			var order   = new ExpressionContext(buildInfo.Parent, sequence, lambda);
			var body    = lambda.Body.Unwrap();
			var sql     = builder.ConvertExpressions(order, body, ConvertFlags.Key);

			builder.ReplaceParent(order, sparent);

			//if (!methodCall.Method.Name.StartsWith("Then"))
			//	sequence.SqlQuery.OrderBy.Items.Clear();

			foreach (var expr in sql)
			{
				var e = builder.ConvertSearchCondition(sequence, expr.Sql);
				sequence.SqlQuery.OrderBy.Expr(e, methodCall.Method.Name.EndsWith("Descending"));
			}

			return sequence;
		}
예제 #3
0
		protected override SequenceConvertInfo Convert(
			ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
		{
			var predicate = (LambdaExpression)methodCall.Arguments[1].Unwrap();
			var info      = builder.ConvertSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]), predicate.Parameters[0]);

			if (info != null)
			{
				info.Expression = methodCall.Convert(ex => ConvertMethod(methodCall, 0, info, predicate.Parameters[0], ex));

				if (param != null)
				{
					if (param.Type != info.Parameter.Type)
						param = Expression.Parameter(info.Parameter.Type, param.Name);

					if (info.ExpressionsToReplace != null)
						foreach (var path in info.ExpressionsToReplace)
						{
							path.Path = path.Path.Convert(e => e == info.Parameter ? param : e);
							path.Expr = path.Expr.Convert(e => e == info.Parameter ? param : e);
						}
				}

				info.Parameter = param;

				return info;
			}

			return null;
		}
예제 #4
0
		static void BuildSkip(ExpressionBuilder builder, IBuildContext sequence, ISqlExpression prevSkipValue, ISqlExpression expr)
		{
			var sql = sequence.SqlQuery;

			builder.SqlProvider.SqlQuery = sql;

			sql.Select.Skip(expr);

			builder.SqlProvider.SqlQuery = sql;

			if (sql.Select.TakeValue != null)
			{
				if (builder.SqlProvider.IsSkipSupported || !builder.SqlProvider.IsTakeSupported)
					sql.Select.Take(builder.Convert(
						sequence,
						new SqlBinaryExpression(typeof(int), sql.Select.TakeValue, "-", sql.Select.SkipValue, Precedence.Additive)));

				if (prevSkipValue != null)
					sql.Select.Skip(builder.Convert(
						sequence,
						new SqlBinaryExpression(typeof(int), prevSkipValue, "+", sql.Select.SkipValue, Precedence.Additive)));
			}

			if (!builder.SqlProvider.TakeAcceptsParameter)
			{
				var p = sql.Select.SkipValue as SqlParameter;

				if (p != null)
					p.IsQueryParameter = false;
			}
		}
예제 #5
0
		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			var sequence  = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
			var condition = (LambdaExpression)methodCall.Arguments[1].Unwrap();
			var result    = builder.BuildWhere(buildInfo.Parent, sequence, condition, true);

			result.SetAlias(condition.Parameters[0].Name);

			return result;
		}
예제 #6
0
		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
			var sql      = sequence.SqlQuery;

			if (sql.Select.TakeValue != null || sql.Select.SkipValue != null)
				sequence = new SubQueryContext(sequence);

			sequence.SqlQuery.Select.IsDistinct = true;

			return sequence;
		}
예제 #7
0
		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			var sequence1 = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
			var sequence2 = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SqlQuery()));
			var union     = new SqlQuery.Union(sequence2.SqlQuery, methodCall.Method.Name == "Concat");

			var sq = sequence1 as SubQueryContext;

			if (sq == null || sq.Union != null || !sq.SqlQuery.IsSimple)
				sq = new SubQueryContext(sequence1);

			sq.SubQuery.SqlQuery.Unions.Add(union);
			sq.Union = sequence2;

			return sq;
		}
예제 #8
0
		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

			var table = (TableBuilder.TableContext)sequence;
			var value = (string)((ConstantExpression)methodCall.Arguments[1]).Value;

			switch (methodCall.Method.Name)
			{
				case "TableName"    : table.SqlTable.PhysicalName = value; break;
				case "DatabaseName" : table.SqlTable.Database     = value; break;
				case "OwnerName"    : table.SqlTable.Owner        = value; break;
			}

			return sequence;
		}
예제 #9
0
		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			var sequence     = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
			var defaultValue = methodCall.Arguments.Count == 1 ? null : methodCall.Arguments[1].Unwrap();

			if (buildInfo.Parent is SelectManyBuilder.SelectManyContext)
			{
				var groupJoin = ((SelectManyBuilder.SelectManyContext)buildInfo.Parent).Sequence[0] as JoinBuilder.GroupJoinContext;

				if (groupJoin != null)
				{
					groupJoin.SqlQuery.From.Tables[0].Joins[0].JoinType = SqlQuery.JoinType.Left;
					groupJoin.SqlQuery.From.Tables[0].Joins[0].IsWeak   = false;
				}
			}

			return new DefaultIfEmptyContext(buildInfo.Parent, sequence, defaultValue);
		}
예제 #10
0
		static void BuildTake(ExpressionBuilder builder, IBuildContext sequence, ISqlExpression expr)
		{
			var sql = sequence.SqlQuery;

			builder.SqlProvider.SqlQuery = sql;

			sql.Select.Take(expr);

			if (sql.Select.SkipValue != null && builder.SqlProvider.IsTakeSupported && !builder.SqlProvider.IsSkipSupported)
			{
				if (sql.Select.SkipValue is SqlParameter && sql.Select.TakeValue is SqlValue)
				{
					var skip = (SqlParameter)sql.Select.SkipValue;
					var parm = (SqlParameter)sql.Select.SkipValue.Clone(new Dictionary<ICloneableElement,ICloneableElement>(), _ => true);

					parm.SetTakeConverter((int)((SqlValue)sql.Select.TakeValue).Value);

					sql.Select.Take(parm);

					var ep = (from pm in builder.CurrentSqlParameters where pm.SqlParameter == skip select pm).First();

					ep = new ParameterAccessor
					{
						Expression   = ep.Expression,
						Accessor     = ep.Accessor,
						SqlParameter = parm
					};

					builder.CurrentSqlParameters.Add(ep);
				}
				else
					sql.Select.Take(builder.Convert(
						sequence,
						new SqlBinaryExpression(typeof(int), sql.Select.SkipValue, "+", sql.Select.TakeValue, Precedence.Additive)));
			}

			if (!builder.SqlProvider.TakeAcceptsParameter)
			{
				var p = sql.Select.TakeValue as SqlParameter;

				if (p != null)
					p.IsQueryParameter = false;
			}
		}
예제 #11
0
		protected override SequenceConvertInfo Convert(
			ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
		{
			var info = builder.ConvertSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]), null);

			if (info != null)
			{
				info.Expression =
					Expression.Call(
						methodCall.Method.DeclaringType,
						methodCall.Method.Name,
						new[] { info.Expression.Type.GetGenericArguments()[0] },
						info.Expression, methodCall.Arguments[1]);
				info.Parameter  = param;

				return info;
			}

			return null;
		}
예제 #12
0
		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
			var table    = sequence as TableBuilder.TableContext;

			if (table != null && table.InheritanceMapping.Count > 0)
			{
				var objectType = methodCall.Type.GetGenericArguments()[0];

				if (TypeHelper.IsSameOrParent(table.ObjectType, objectType))
				{
					var predicate = builder.MakeIsPredicate(table, objectType);

					if (predicate.GetType() != typeof(SqlQuery.Predicate.Expr))
						sequence.SqlQuery.Where.SearchCondition.Conditions.Add(new SqlQuery.Condition(false, predicate));
				}
			}

			return sequence;
		}
예제 #13
0
		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

			var arg = methodCall.Arguments[1].Unwrap();

			if (arg.NodeType == ExpressionType.Lambda)
				arg = ((LambdaExpression)arg).Body.Unwrap();

			var expr = builder.ConvertToSql(sequence, arg, false);

			if (methodCall.Method.Name == "Take")
			{
				BuildTake(builder, sequence, expr);
			}
			else
			{
				BuildSkip(builder, sequence, sequence.SqlQuery.Select.SkipValue, expr);
			}

			return sequence;
		}
예제 #14
0
		protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			if (!methodCall.IsQueryable("OrderBy", "OrderByDescending", "ThenBy", "ThenByDescending"))
				return false;

			var body = ((LambdaExpression)methodCall.Arguments[1].Unwrap()).Body.Unwrap();

			if (body.NodeType == ExpressionType.MemberInit)
			{
				var mi = (MemberInitExpression)body;
				bool throwExpr;

				if (mi.NewExpression.Arguments.Count > 0 || mi.Bindings.Count == 0)
					throwExpr = true;
				else
					throwExpr = mi.Bindings.Any(b => b.BindingType != MemberBindingType.Assignment);

				if (throwExpr)
					throw new NotSupportedException(string.Format("Explicit construction of entity type '{0}' in order by is not allowed.", body.Type));
			}

			return true;
		}
예제 #15
0
		protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			return methodCall.IsQueryable("Skip", "Take");
		}
예제 #16
0
 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
 {
     return(methodCall.Arguments.Count == 2 && methodCall.IsQueryable("Concat", "Union"));
 }
예제 #17
0
		public bool CanBuild(ExpressionBuilder builder, BuildInfo buildInfo)
		{
			if (buildInfo.Expression.NodeType == ExpressionType.Call)
				return CanBuildMethodCall(builder, (MethodCallExpression)buildInfo.Expression, buildInfo);
			return false;
		}
예제 #18
0
		protected abstract bool            CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo);
예제 #19
0
		protected abstract SequenceConvertInfo Convert           (ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param);
예제 #20
0
		public SequenceConvertInfo Convert(ExpressionBuilder builder, BuildInfo buildInfo, ParameterExpression param)
		{
			return Convert(builder, (MethodCallExpression)buildInfo.Expression, buildInfo, param);
		}
예제 #21
0
 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
 {
     return(methodCall.IsQueryable("DefaultIfEmpty"));
 }
예제 #22
0
 protected abstract IBuildContext       BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo);
예제 #23
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

            var isSubQuery = sequence.SqlQuery.Select.IsDistinct;

            if (isSubQuery)
            {
                sequence = new SubQueryContext(sequence);
            }

            switch (methodCall.Arguments.Count)
            {
            case 1:
                // static int Insert<T>              (this IValueInsertable<T> source)
                // static int Insert<TSource,TTarget>(this ISelectInsertable<TSource,TTarget> source)
            {
                foreach (var item in sequence.SqlQuery.Insert.Items)
                {
                    sequence.SqlQuery.Select.Expr(item.Expression);
                }
                break;
            }

            case 2:                      // static int Insert<T>(this Table<T> target, Expression<Func<T>> setter)
            {
                UpdateBuilder.BuildSetter(
                    builder,
                    buildInfo,
                    (LambdaExpression)methodCall.Arguments[1].Unwrap(),
                    sequence,
                    sequence.SqlQuery.Insert.Items,
                    sequence);

                sequence.SqlQuery.Insert.Into = ((TableBuilder.TableContext)sequence).SqlTable;
                sequence.SqlQuery.From.Tables.Clear();

                break;
            }

            case 3:                      // static int Insert<TSource,TTarget>(this IQueryable<TSource> source, Table<TTarget> target, Expression<Func<TSource,TTarget>> setter)
            {
                var into = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SqlQuery()));

                UpdateBuilder.BuildSetter(
                    builder,
                    buildInfo,
                    (LambdaExpression)methodCall.Arguments[2].Unwrap(),
                    into,
                    sequence.SqlQuery.Insert.Items,
                    sequence);

                sequence.SqlQuery.Select.Columns.Clear();

                foreach (var item in sequence.SqlQuery.Insert.Items)
                {
                    sequence.SqlQuery.Select.Columns.Add(new SqlQuery.Column(sequence.SqlQuery, item.Expression));
                }

                sequence.SqlQuery.Insert.Into = ((TableBuilder.TableContext)into).SqlTable;

                break;
            }
            }

            var insert = sequence.SqlQuery.Insert;

            var q = insert.Into.Fields.Values.Cast <ISqlExpression>().Except(insert.Items.Select(e => e.Column))
                    .OfType <SqlField>()
                    .Where(f => f.IsIdentity);

            foreach (var field in q)
            {
                var expr = builder.SqlProvider.GetIdentityExpression(insert.Into, field, false);

                if (expr != null)
                {
                    insert.Items.Insert(0, new SqlQuery.SetExpression(field, expr));

                    if (methodCall.Arguments.Count == 3)
                    {
                        sequence.SqlQuery.Select.Columns.Insert(0, new SqlQuery.Column(sequence.SqlQuery, insert.Items[0].Expression));
                    }
                }
            }

            sequence.SqlQuery.QueryType           = QueryType.Insert;
            sequence.SqlQuery.Insert.WithIdentity = methodCall.Method.Name == "InsertWithIdentity";

            return(new InsertContext(buildInfo.Parent, sequence, sequence.SqlQuery.Insert.WithIdentity));
        }
예제 #24
0
 protected override SequenceConvertInfo Convert(
     ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
 {
     return(null);
 }
예제 #25
0
 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
 {
     return(methodCall.IsQueryable("Insert", "InsertWithIdentity"));
 }
예제 #26
0
 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
 {
     return(methodCall.IsQueryable(MethodNames));
 }
예제 #27
0
 public bool CanBuild(ExpressionBuilder builder, BuildInfo buildInfo)
 {
     return(Find(builder, buildInfo, (n, _) => n > 0));
 }
예제 #28
0
        static T Find <T>(ExpressionBuilder builder, BuildInfo buildInfo, Func <int, IBuildContext, T> action)
        {
            var expression = buildInfo.Expression;

            switch (expression.NodeType)
            {
            case ExpressionType.Constant:
            {
                var c = (ConstantExpression)expression;
                if (c.Value is IQueryable)
                {
                    return(action(1, null));
                }

                break;
            }

            case ExpressionType.Call:
            {
                var mc = (MethodCallExpression)expression;

                if (mc.Method.Name == "GetTable")
                {
                    if (expression.Type.IsGenericType && expression.Type.GetGenericTypeDefinition() == typeof(Table <>))
                    {
                        return(action(2, null));
                    }
                }

                break;
            }

            case ExpressionType.MemberAccess:

                if (expression.Type.IsGenericType && expression.Type.GetGenericTypeDefinition() == typeof(Table <>))
                {
                    return(action(3, null));
                }

                // Looking for association.
                //
                if (buildInfo.IsSubQuery && buildInfo.SqlQuery.From.Tables.Count == 0)
                {
                    var ctx = builder.GetContext(buildInfo.Parent, expression);
                    if (ctx != null)
                    {
                        return(action(4, ctx));
                    }
                }

                break;

            case ExpressionType.Parameter:
            {
                if (buildInfo.IsSubQuery && buildInfo.SqlQuery.From.Tables.Count == 0)
                {
                    var ctx = builder.GetContext(buildInfo.Parent, expression);
                    if (ctx != null)
                    {
                        return(action(4, ctx));
                    }
                }

                break;
            }
            }

            return(action(0, null));
        }
예제 #29
0
		protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			return methodCall.IsQueryable("TableName", "DatabaseName", "OwnerName");
		}
예제 #30
0
 public bool IsSequence(ExpressionBuilder builder, BuildInfo buildInfo)
 {
     return(builder.IsSequence(new BuildInfo(buildInfo, ((MethodCallExpression)buildInfo.Expression).Arguments[0])));
 }
예제 #31
0
		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			return builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
		}
예제 #32
0
 public SequenceConvertInfo Convert(ExpressionBuilder builder, BuildInfo buildInfo, ParameterExpression param)
 {
     return(Convert(builder, (MethodCallExpression)buildInfo.Expression, buildInfo, param));
 }
예제 #33
0
		protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			return methodCall.IsQueryable("DefaultIfEmpty");
		}
예제 #34
0
		public bool IsSequence(ExpressionBuilder builder, BuildInfo buildInfo)
		{
			return builder.IsSequence(new BuildInfo(buildInfo, ((MethodCallExpression)buildInfo.Expression).Arguments[0]));
		}
예제 #35
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

            switch (methodCall.Arguments.Count)
            {
            case 1:                      // int Update<T>(this IUpdateable<T> source)
                break;

            case 2:                      // int Update<T>(this IQueryable<T> source, Expression<Func<T,T>> setter)
            {
                BuildSetter(
                    builder,
                    buildInfo,
                    (LambdaExpression)methodCall.Arguments[1].Unwrap(),
                    sequence,
                    sequence.SqlQuery.Update.Items,
                    sequence);
                break;
            }

            case 3:
            {
                var expr = methodCall.Arguments[1].Unwrap();

                if (expr is LambdaExpression)
                {
                    // int Update<T>(this IQueryable<T> source, Expression<Func<T,bool>> predicate, Expression<Func<T,T>> setter)
                    //
                    sequence = builder.BuildWhere(buildInfo.Parent, sequence, (LambdaExpression)methodCall.Arguments[1].Unwrap(), false);

                    BuildSetter(
                        builder,
                        buildInfo,
                        (LambdaExpression)methodCall.Arguments[2].Unwrap(),
                        sequence,
                        sequence.SqlQuery.Update.Items,
                        sequence);
                }
                else
                {
                    // static int Update<TSource,TTarget>(this IQueryable<TSource> source, Table<TTarget> target, Expression<Func<TSource,TTarget>> setter)
                    //
                    var into = builder.BuildSequence(new BuildInfo(buildInfo, expr, new SqlQuery()));

                    BuildSetter(
                        builder,
                        buildInfo,
                        (LambdaExpression)methodCall.Arguments[2].Unwrap(),
                        into,
                        sequence.SqlQuery.Update.Items,
                        sequence);

                    var sql = sequence.SqlQuery;

                    sql.Select.Columns.Clear();

                    foreach (var item in sql.Update.Items)
                    {
                        sql.Select.Columns.Add(new SqlQuery.Column(sql, item.Expression));
                    }

                    sql.Update.Table = ((TableBuilder.TableContext)into).SqlTable;
                }

                break;
            }
            }

            sequence.SqlQuery.QueryType = QueryType.Update;

            return(new UpdateContext(buildInfo.Parent, sequence));
        }
예제 #36
0
		public IBuildContext BuildSequence(ExpressionBuilder builder, BuildInfo buildInfo)
		{
			return BuildMethodCall(builder, (MethodCallExpression)buildInfo.Expression, buildInfo);
		}
예제 #37
0
 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
 {
     return(builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])));
 }
예제 #38
0
		protected abstract IBuildContext BuildMethodCall   (ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo);
예제 #39
0
		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			var isGroup      = methodCall.Method.Name == "GroupJoin";
			var outerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0], buildInfo.SqlQuery));
			var innerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SqlQuery()));
			var countContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SqlQuery()));

			var context  = new SubQueryContext(outerContext);
			innerContext = isGroup ? new GroupJoinSubQueryContext(innerContext, methodCall) : new SubQueryContext(innerContext);
			countContext = new SubQueryContext(countContext);

			var join = innerContext.SqlQuery.InnerJoin();
			var sql  = context.SqlQuery;

			sql.From.Tables[0].Joins.Add(join.JoinedTable);

			var selector = (LambdaExpression)methodCall.Arguments[4].Unwrap();

			context.SetAlias(selector.Parameters[0].Name);
			innerContext.SetAlias(selector.Parameters[1].Name);

			var outerKeyLambda = ((LambdaExpression)methodCall.Arguments[2].Unwrap());
			var innerKeyLambda = ((LambdaExpression)methodCall.Arguments[3].Unwrap());

			var outerKeySelector = outerKeyLambda.Body.Unwrap();
			var innerKeySelector = innerKeyLambda.Body.Unwrap();

			var outerParent = context.     Parent;
			var innerParent = innerContext.Parent;
			var countParent = countContext.Parent;

			var outerKeyContext = new ExpressionContext(buildInfo.Parent, context,      outerKeyLambda);
			var innerKeyContext = new ExpressionContext(buildInfo.Parent, innerContext, innerKeyLambda);
			var countKeyContext = new ExpressionContext(buildInfo.Parent, countContext, innerKeyLambda);

			// Process counter.
			//
			var counterSql = ((SubQueryContext)countContext).SqlQuery;

			// Make join and where for the counter.
			//
			if (outerKeySelector.NodeType == ExpressionType.New)
			{
				var new1 = (NewExpression)outerKeySelector;
				var new2 = (NewExpression)innerKeySelector;

				for (var i = 0; i < new1.Arguments.Count; i++)
				{
					var arg1 = new1.Arguments[i];
					var arg2 = new2.Arguments[i];

					BuildJoin(builder, join, outerKeyContext, arg1, innerKeyContext, arg2, countKeyContext, counterSql);
				}
			}
			else if (outerKeySelector.NodeType == ExpressionType.MemberInit)
			{
				var mi1 = (MemberInitExpression)outerKeySelector;
				var mi2 = (MemberInitExpression)innerKeySelector;

				for (var i = 0; i < mi1.Bindings.Count; i++)
				{
					if (mi1.Bindings[i].Member != mi2.Bindings[i].Member)
						throw new LinqException(string.Format("List of member inits does not match for entity type '{0}'.", outerKeySelector.Type));

					var arg1 = ((MemberAssignment)mi1.Bindings[i]).Expression;
					var arg2 = ((MemberAssignment)mi2.Bindings[i]).Expression;

					BuildJoin(builder, join, outerKeyContext, arg1, innerKeyContext, arg2, countKeyContext, counterSql);
				}
			}
			else
			{
				BuildJoin(builder, join, outerKeyContext, outerKeySelector, innerKeyContext, innerKeySelector, countKeyContext, counterSql);
			}

			context.     Parent = outerParent;
			innerContext.Parent = innerParent;
			countContext.Parent = countParent;

			if (isGroup)
			{
				counterSql.ParentSql = sql;
				counterSql.Select.Columns.Clear();

				var inner = (GroupJoinSubQueryContext)innerContext;

				inner.Join       = join.JoinedTable;
				inner.CounterSql = counterSql;
				return new GroupJoinContext(buildInfo.Parent, selector, context, inner);
			}

			return new JoinContext(buildInfo.Parent, selector, context, innerContext);
		}
예제 #40
0
 public IBuildContext BuildSequence(ExpressionBuilder builder, BuildInfo buildInfo)
 {
     return(BuildMethodCall(builder, (MethodCallExpression)buildInfo.Expression, buildInfo));
 }
예제 #41
0
		static void BuildJoin(
			ExpressionBuilder        builder,
			SqlQuery.FromClause.Join join,
			ExpressionContext outerKeyContext, Expression outerKeySelector,
			ExpressionContext innerKeyContext, Expression innerKeySelector,
			ExpressionContext countKeyContext, SqlQuery countSql)
		{
			var predicate = builder.ConvertObjectComparison(
				ExpressionType.Equal,
				outerKeyContext, outerKeySelector,
				innerKeyContext, innerKeySelector);

			if (predicate != null)
				join.JoinedTable.Condition.Conditions.Add(new SqlQuery.Condition(false, predicate));
			else
				join
					.Expr(builder.ConvertToSql(outerKeyContext, outerKeySelector)).Equal
					.Expr(builder.ConvertToSql(innerKeyContext, innerKeySelector));

			predicate = builder.ConvertObjectComparison(
				ExpressionType.Equal,
				outerKeyContext, outerKeySelector,
				countKeyContext, innerKeySelector);

			if (predicate != null)
				countSql.Where.SearchCondition.Conditions.Add(new SqlQuery.Condition(false, predicate));
			else
				countSql.Where
					.Expr(builder.ConvertToSql(outerKeyContext, outerKeySelector)).Equal
					.Expr(builder.ConvertToSql(countKeyContext, innerKeySelector));
		}
예제 #42
0
        internal static void ParseSet(
            ExpressionBuilder builder,
            BuildInfo buildInfo,
            LambdaExpression extract,
            LambdaExpression update,
            IBuildContext select,
            SqlTable table,
            List <SqlQuery.SetExpression> items)
        {
            var ext = extract.Body;

            while (ext.NodeType == ExpressionType.Convert || ext.NodeType == ExpressionType.ConvertChecked)
            {
                ext = ((UnaryExpression)ext).Operand;
            }

            if (ext.NodeType != ExpressionType.MemberAccess || ext.GetRootObject() != extract.Parameters[0])
            {
                throw new LinqException("Member expression expected for the 'Set' statement.");
            }

            var body   = (MemberExpression)ext;
            var member = body.Member;

            if (member is MethodInfo)
            {
                member = TypeHelper.GetPropertyByMethod((MethodInfo)member);
            }

            var members = body.GetMembers();
            var name    = members
                          .Skip(1)
                          .Select(ex =>
            {
                var me = ex as MemberExpression;

                if (me == null)
                {
                    return(null);
                }

                var m = me.Member;

                if (m is MethodInfo)
                {
                    m = TypeHelper.GetPropertyByMethod((MethodInfo)m);
                }

                return(m);
            })
                          .Where(m => m != null && !TypeHelper.IsNullableValueMember(m))
                          .Select(m => m.Name)
                          .Aggregate((s1, s2) => s1 + "." + s2);

            if (table != null && !table.Fields.ContainsKey(name))
            {
                throw new LinqException("Member '{0}.{1}' is not a table column.", member.DeclaringType.Name, name);
            }

            var column = table != null ?
                         table.Fields[name] :
                         select.ConvertToSql(
                body, 1, ConvertFlags.Field)[0].Sql;
            //Expression.MakeMemberAccess(Expression.Parameter(member.DeclaringType, "p"), member), 1, ConvertFlags.Field)[0].Sql;
            var sp   = select.Parent;
            var ctx  = new ExpressionContext(buildInfo.Parent, select, update);
            var expr = builder.ConvertToSqlExpression(ctx, update.Body);

            builder.ReplaceParent(ctx, sp);

            if (expr is SqlParameter && update.Body.Type.IsEnum)
            {
                ((SqlParameter)expr).SetEnumConverter(update.Body.Type, builder.MappingSchema);
            }

            items.Add(new SqlQuery.SetExpression(column, expr));
        }
예제 #43
0
		protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			return methodCall.IsQueryable("Concat", "Union") && methodCall.Arguments.Count == 2;
		}
예제 #44
0
		protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
		{
			return methodCall.Arguments.Count == 2 && methodCall.IsQueryable("Except", "Intersect");
		}
예제 #45
0
 protected TableContext(ExpressionBuilder builder, SqlQuery sqlQuery)
 {
     Builder  = builder;
     SqlQuery = sqlQuery;
 }
예제 #46
0
 protected abstract bool                CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo);
예제 #47
0
 protected abstract SequenceConvertInfo Convert(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param);
예제 #48
0
		protected override SequenceConvertInfo Convert(
			ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
		{
			return null;
		}
예제 #49
0
        protected override SequenceConvertInfo Convert(
            ExpressionBuilder builder, MethodCallExpression originalMethodCall, BuildInfo buildInfo, ParameterExpression param)
        {
            var methodCall = originalMethodCall;
            var selector   = (LambdaExpression)methodCall.Arguments[1].Unwrap();
            var info       = builder.ConvertSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]), selector.Parameters[0]);

            if (info != null)
            {
                methodCall = (MethodCallExpression)methodCall.Convert(
                    ex => ConvertMethod(methodCall, 0, info, selector.Parameters[0], ex));
                selector = (LambdaExpression)methodCall.Arguments[1].Unwrap();
            }

            if (param != null && param != builder.SequenceParameter)
            {
                var list =
                    (
                        from path in GetExpressions(selector.Parameters[0], param, 0, selector.Body.Unwrap())
                        orderby path.Level descending
                        select path
                    ).ToList();

                if (list.Count > 0)
                {
                    var plist = list.Where(e => e.Expr == selector.Parameters[0]).ToList();

                    if (plist.Count > 1)
                    {
                        list = list.Except(plist.Skip(1)).ToList();
                    }

                    var p = plist.FirstOrDefault();

                    if (p == null)
                    {
                        var types  = methodCall.Method.GetGenericArguments();
                        var mgen   = methodCall.Method.GetGenericMethodDefinition();
                        var btype  = typeof(ExpressionHoder <,>).MakeGenericType(types[0], selector.Body.Type);
                        var fields = btype.GetFields();
                        var pold   = selector.Parameters[0];
                        var psel   = Expression.Parameter(types[0], pold.Name);

                        methodCall = Expression.Call(
                            methodCall.Object,
                            mgen.MakeGenericMethod(types[0], btype),
                            methodCall.Arguments[0],
                            Expression.Lambda(
                                Expression.MemberInit(
                                    Expression.New(btype),
                                    Expression.Bind(fields[0], psel),
                                    Expression.Bind(fields[1], selector.Body.Convert(e => e == pold ? psel : e))),
                                psel));

                        selector = (LambdaExpression)methodCall.Arguments[1].Unwrap();
                        param    = Expression.Parameter(selector.Body.Type, param.Name);

                        list.Add(new SequenceConvertPath {
                            Path = param, Expr = Expression.MakeMemberAccess(param, fields[1]), Level = 1
                        });

                        var expr = Expression.MakeMemberAccess(param, fields[0]);

                        foreach (var t in list)
                        {
                            t.Expr = t.Expr.Convert(ex => ex == pold ? expr : ex);
                        }

                        return(new SequenceConvertInfo
                        {
                            Parameter = param,
                            Expression = methodCall,
                            ExpressionsToReplace = list
                        });
                    }

                    if (info != null)
                    {
                        if (info.ExpressionsToReplace != null)
                        {
                            foreach (var path in info.ExpressionsToReplace)
                            {
                                path.Path   = path.Path.Convert(e => e == info.Parameter ? p.Path : e);
                                path.Expr   = path.Expr.Convert(e => e == info.Parameter ? p.Path : e);
                                path.Level += p.Level;

                                list.Add(path);
                            }

                            list = list.OrderByDescending(path => path.Level).ToList();
                        }
                    }

                    if (list.Count > 1)
                    {
                        return(new SequenceConvertInfo
                        {
                            Parameter = param,
                            Expression = methodCall,
                            ExpressionsToReplace = list
                                                   .Where(e => e != p)
                                                   .Select(ei =>
                            {
                                ei.Expr = ei.Expr.Convert(e => e == p.Expr ? p.Path : e);
                                return ei;
                            })
                                                   .ToList()
                        });
                    }
                }
            }

            if (methodCall != originalMethodCall)
            {
                return new SequenceConvertInfo
                       {
                           Parameter  = param,
                           Expression = methodCall,
                       }
            }
            ;

            return(null);
        }
예제 #50
0
 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
 {
     return(methodCall.IsQueryable("TableName", "DatabaseName", "OwnerName"));
 }
예제 #51
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence           = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
            var collectionSelector = (LambdaExpression)methodCall.Arguments[1].Unwrap();
            var resultSelector     = (LambdaExpression)methodCall.Arguments[2].Unwrap();

            if (!sequence.SqlQuery.GroupBy.IsEmpty)
            {
                sequence = new SubQueryContext(sequence);
            }

            var context = new SelectManyContext(buildInfo.Parent, collectionSelector, sequence);
            var expr    = collectionSelector.Body.Unwrap();

            var collectionInfo = new BuildInfo(context, expr, new SqlQuery());
            var collection     = builder.BuildSequence(collectionInfo);
            var leftJoin       = collection is DefaultIfEmptyBuilder.DefaultIfEmptyContext;
            var sql            = collection.SqlQuery;

            var sequenceTable = sequence.SqlQuery.From.Tables[0].Source;
            var newQuery      = null != new QueryVisitor().Find(sql, e => e == collectionInfo.SqlQuery);
            var crossApply    = null != new QueryVisitor().Find(sql, e =>
                                                                e == sequenceTable ||
                                                                e.ElementType == QueryElementType.SqlField && sequenceTable == ((SqlField)e).Table ||
                                                                e.ElementType == QueryElementType.Column && sequenceTable == ((SqlQuery.Column)e).Parent);

            if (collection is JoinBuilder.GroupJoinSubQueryContext)
            {
                var groupJoin = ((JoinBuilder.GroupJoinSubQueryContext)collection).GroupJoin;

                groupJoin.SqlQuery.From.Tables[0].Joins[0].JoinType = SqlQuery.JoinType.Inner;
                groupJoin.SqlQuery.From.Tables[0].Joins[0].IsWeak   = false;
            }

            if (!newQuery)
            {
                context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false);
                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }

            if (!crossApply)
            {
                if (!leftJoin)
                {
                    context.Collection = new SubQueryContext(collection, sequence.SqlQuery, true);
                    return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
                }
                else
                {
                    var join = SqlQuery.OuterApply(sql);
                    sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable);
                    context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false);

                    return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
                }
            }

            if (collection is TableBuilder.TableContext)
            {
                var table = (TableBuilder.TableContext)collection;

                var join = table.SqlTable.TableArguments != null && table.SqlTable.TableArguments.Length > 0 ?
                           leftJoin ? SqlQuery.OuterApply(sql) : SqlQuery.CrossApply(sql) :
                           leftJoin?SqlQuery.LeftJoin(sql) : SqlQuery.InnerJoin(sql);

                join.JoinedTable.Condition.Conditions.AddRange(sql.Where.SearchCondition.Conditions);

                sql.Where.SearchCondition.Conditions.Clear();

                var collectionParent = collection.Parent as TableBuilder.TableContext;

                // Association.
                //
                if (collectionParent != null && collectionInfo.IsAssociationBuilt)
                {
                    var ts = (SqlQuery.TableSource) new QueryVisitor().Find(sequence.SqlQuery.From, e =>
                    {
                        if (e.ElementType == QueryElementType.TableSource)
                        {
                            var t = (SqlQuery.TableSource)e;
                            return(t.Source == collectionParent.SqlTable);
                        }

                        return(false);
                    });

                    ts.Joins.Add(join.JoinedTable);
                }
                else
                {
                    sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable);
                }

                context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false);
                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }
            else
            {
                var join = leftJoin ? SqlQuery.OuterApply(sql) : SqlQuery.CrossApply(sql);
                sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable);

                context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false);
                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }
        }