protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var mergeContext = (MergeContext)builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); var statement = mergeContext.Merge; var operation = new SqlMergeOperationClause(MergeOperationType.DeleteBySource); statement.Operations.Add(operation); var predicate = methodCall.Arguments[1]; if (!(predicate is ConstantExpression constPredicate) || constPredicate.Value != null) { var condition = (LambdaExpression)predicate.Unwrap(); var conditionExpr = builder.ConvertExpression(condition.Body.Unwrap()); operation.Where = new SqlSearchCondition(); builder.BuildSearchCondition( new ExpressionContext(null, new[] { mergeContext.TargetContext }, condition), conditionExpr, operation.Where.Conditions, false); } return(mergeContext); }
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var mergeContext = (MergeContext)builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); var statement = mergeContext.Merge; if (methodCall.Arguments.Count == 2) { // On<TTarget, TSource>(IMergeableOn<TTarget, TSource> merge, Expression<Func<TTarget, TSource, bool>> matchCondition) var predicate = methodCall.Arguments[1]; var condition = (LambdaExpression)predicate.Unwrap(); var conditionExpr = builder.ConvertExpression(condition.Body.Unwrap()); mergeContext.AddTargetParameter(condition.Parameters[0]); mergeContext.AddSourceParameter(condition.Parameters[1]); builder.BuildSearchCondition( new ExpressionContext(null, new[] { mergeContext.TargetContext, mergeContext.SourceContext }, condition), conditionExpr, statement.On.Conditions, false); } else if (methodCall.Arguments.Count == 3) { var targetKeyLambda = ((LambdaExpression)methodCall.Arguments[1].Unwrap()); var sourceKeyLambda = ((LambdaExpression)methodCall.Arguments[2].Unwrap()); var targetKeySelector = targetKeyLambda.Body.Unwrap(); var sourceKeySelector = sourceKeyLambda.Body.Unwrap(); var targetKeyContext = new ExpressionContext(buildInfo.Parent, mergeContext.TargetContext, targetKeyLambda); var sourceKeyContext = new ExpressionContext(buildInfo.Parent, mergeContext.SourceContext, sourceKeyLambda); if (targetKeySelector.NodeType == ExpressionType.New) { var new1 = (NewExpression)targetKeySelector; var new2 = (NewExpression)sourceKeySelector; for (var i = 0; i < new1.Arguments.Count; i++) { var arg1 = new1.Arguments[i]; var arg2 = new2.Arguments[i]; JoinBuilder.BuildJoin(builder, statement.On, targetKeyContext, arg1, sourceKeyContext, arg2); } } else if (targetKeySelector.NodeType == ExpressionType.MemberInit) { // TODO: migrate unordered members support to original code var mi1 = (MemberInitExpression)targetKeySelector; var mi2 = (MemberInitExpression)sourceKeySelector; if (mi1.Bindings.Count != mi2.Bindings.Count) { throw new LinqException($"List of member inits does not match for entity type '{targetKeySelector.Type}'."); } for (var i = 0; i < mi1.Bindings.Count; i++) { var binding2 = (MemberAssignment)mi2.Bindings.Where(b => b.Member == mi1.Bindings[i].Member).FirstOrDefault(); if (binding2 == null) { throw new LinqException($"List of member inits does not match for entity type '{targetKeySelector.Type}'."); } var arg1 = ((MemberAssignment)mi1.Bindings[i]).Expression; var arg2 = binding2.Expression; JoinBuilder.BuildJoin(builder, statement.On, targetKeyContext, arg1, sourceKeyContext, arg2); } } else { JoinBuilder.BuildJoin(builder, statement.On, targetKeyContext, targetKeySelector, sourceKeyContext, sourceKeySelector); } } else { // OnTargetKey<TTarget>(IMergeableOn<TTarget, TTarget> merge) var targetType = methodCall.Method.GetGenericArguments()[0]; var pTarget = Expression.Parameter(targetType, "t"); var pSource = Expression.Parameter(targetType, "s"); var targetDescriptor = builder.MappingSchema.GetEntityDescriptor(targetType); Expression?ex = null; for (var i = 0; i < targetDescriptor.Columns.Count; i++) { var column = targetDescriptor.Columns[i]; if (!column.IsPrimaryKey) { continue; } var expr = Expression.Equal( Expression.MakeMemberAccess(pTarget, column.MemberInfo), Expression.MakeMemberAccess(pSource, column.MemberInfo)); ex = ex != null?Expression.AndAlso(ex, expr) : expr; } if (ex == null) { throw new LinqToDBException("Method OnTargetKey() needs at least one primary key column"); } var condition = Expression.Lambda(ex, pTarget, pSource); builder.BuildSearchCondition( new ExpressionContext(null, new[] { mergeContext.TargetContext, mergeContext.SourceContext }, condition), ex, statement.On.Conditions, false); } mergeContext.SourceContext.MatchBuilt(); return(mergeContext); }
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var outerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0], buildInfo.SelectQuery)); var innerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery())); outerContext = new SubQueryContext(outerContext); innerContext = new SubQueryContext(innerContext); var selector = (LambdaExpression)methodCall.Arguments[methodCall.Arguments.Count - 1].Unwrap(); outerContext.SetAlias(selector.Parameters[0].Name); innerContext.SetAlias(selector.Parameters[1].Name); JoinType joinType; var conditionIndex = 2; switch (methodCall.Method.Name) { case "InnerJoin": joinType = JoinType.Inner; break; case "CrossJoin": joinType = JoinType.Inner; conditionIndex = -1; break; case "LeftJoin": joinType = JoinType.Left; break; case "RightJoin": joinType = JoinType.Right; break; case "FullJoin": joinType = JoinType.Full; break; default: conditionIndex = 3; var joinValue = (SqlJoinType)methodCall.Arguments[2].EvaluateExpression(); switch (joinValue) { case SqlJoinType.Inner: joinType = JoinType.Inner; break; case SqlJoinType.Left: joinType = JoinType.Left; break; case SqlJoinType.Right: joinType = JoinType.Right; break; case SqlJoinType.Full: joinType = JoinType.Full; break; default: throw new ArgumentOutOfRangeException(); } break; } if (conditionIndex != -1) { var condition = (LambdaExpression)methodCall.Arguments[conditionIndex].Unwrap(); var conditionExpr = builder.ConvertExpression(condition.Body.Unwrap()); var join = new SqlFromClause.Join(joinType, innerContext.SelectQuery, null, false, Array <SqlFromClause.Join> .Empty); outerContext.SelectQuery.From.Tables[0].Joins.Add(join.JoinedTable); builder.BuildSearchCondition( new ExpressionContext(null, new[] { outerContext, innerContext }, condition), conditionExpr, join.JoinedTable.Condition.Conditions, false); } else { outerContext.SelectQuery.From.Table(innerContext.SelectQuery); } return(new SelectContext(buildInfo.Parent, selector, outerContext, innerContext) #if DEBUG { MethodCall = methodCall } #endif ); }
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var outerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); var innerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery())); JoinType joinType; var conditionIndex = 2; switch (methodCall.Method.Name) { case "InnerJoin": joinType = JoinType.Inner; break; case "CrossJoin": joinType = JoinType.Inner; conditionIndex = -1; break; case "LeftJoin": joinType = JoinType.Left; break; case "RightJoin": joinType = JoinType.Right; break; case "FullJoin": joinType = JoinType.Full; break; default: conditionIndex = 3; joinType = (SqlJoinType)methodCall.Arguments[2].EvaluateExpression() !switch { SqlJoinType.Inner => JoinType.Inner, SqlJoinType.Left => JoinType.Left, SqlJoinType.Right => JoinType.Right, SqlJoinType.Full => JoinType.Full, _ => throw new InvalidOperationException($"Unexpected join type: {(SqlJoinType)methodCall.Arguments[2].EvaluateExpression()!}") }; break; } if (joinType == JoinType.Right || joinType == JoinType.Full) { outerContext = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, outerContext, null); } outerContext = new SubQueryContext(outerContext); if (joinType == JoinType.Left || joinType == JoinType.Full) { innerContext = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, innerContext, null); } innerContext = new SubQueryContext(innerContext); var selector = (LambdaExpression)methodCall.Arguments[methodCall.Arguments.Count - 1].Unwrap(); outerContext.SetAlias(selector.Parameters[0].Name); innerContext.SetAlias(selector.Parameters[1].Name); var joinContext = new JoinContext(buildInfo.Parent, selector, outerContext, innerContext) #if DEBUG { Debug_MethodCall = methodCall } #endif ; if (conditionIndex != -1) { var condition = (LambdaExpression)methodCall.Arguments[conditionIndex].Unwrap(); var conditionExpr = condition.GetBody(selector.Parameters[0], selector.Parameters[1]); conditionExpr = builder.ConvertExpression(conditionExpr); var join = new SqlFromClause.Join(joinType, innerContext.SelectQuery, null, false, Array <SqlFromClause.Join> .Empty); outerContext.SelectQuery.From.Tables[0].Joins.Add(join.JoinedTable); builder.BuildSearchCondition( joinContext, conditionExpr, @join.JoinedTable.Condition.Conditions); } else { outerContext.SelectQuery.From.Table(innerContext.SelectQuery); } return(joinContext); }
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var mergeContext = (MergeContext)builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); var statement = mergeContext.Merge; var operation = new SqlMergeOperationClause(MergeOperationType.Insert); statement.Operations.Add(operation); var predicate = methodCall.Arguments[1]; var setter = methodCall.Arguments[2]; if (!setter.IsNullValue()) { var setterExpression = (LambdaExpression)setter.Unwrap(); mergeContext.AddSourceParameter(setterExpression.Parameters[0]); UpdateBuilder.BuildSetterWithContext( builder, buildInfo, setterExpression, mergeContext.TargetContext, operation.Items, mergeContext.SourceContext); } else { // build setters like QueryRunner.Insert var sqlTable = (SqlTable)statement.Target.Source; var param = Expression.Parameter(sqlTable.ObjectType, "s"); foreach (var field in sqlTable.Fields) { if (field.IsInsertable) { var expression = LinqToDB.Expressions.Extensions.GetMemberGetter(field.ColumnDescriptor.MemberInfo, param); var tgtExpr = mergeContext.TargetContext.ConvertToSql(builder.ConvertExpression(expression), 1, ConvertFlags.Field)[0].Sql; var srcExpr = mergeContext.SourceContext.ConvertToSql(builder.ConvertExpression(expression), 1, ConvertFlags.Field)[0].Sql; operation.Items.Add(new SqlSetExpression(tgtExpr, srcExpr)); } else if (field.IsIdentity) { var expr = builder.DataContext.CreateSqlProvider().GetIdentityExpression(sqlTable); if (expr != null) { operation.Items.Add(new SqlSetExpression(field, expr)); } } } } if (!predicate.IsNullValue()) { var condition = (LambdaExpression)predicate.Unwrap(); var conditionExpr = builder.ConvertExpression(condition.Body.Unwrap()); operation.Where = new SqlSearchCondition(); builder.BuildSearchCondition( new ExpressionContext(null, new[] { mergeContext.SourceContext }, condition), conditionExpr, operation.Where.Conditions); } return(mergeContext); }