protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var deleteType = methodCall.Method.Name switch { nameof(LinqExtensions.DeleteWithOutput) => DeleteContext.DeleteType.DeleteOutput, nameof(LinqExtensions.DeleteWithOutputInto) => DeleteContext.DeleteType.DeleteOutputInto, _ => DeleteContext.DeleteType.Delete, }; var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); if (methodCall.Arguments.Count == 2 && deleteType == DeleteContext.DeleteType.Delete) { sequence = builder.BuildWhere(buildInfo.Parent, sequence, (LambdaExpression)methodCall.Arguments[1].Unwrap(), false); } var deleteStatement = new SqlDeleteStatement(sequence.SelectQuery); sequence.Statement = deleteStatement; // Check association. // if (sequence is SelectContext ctx && ctx.IsScalar) { var res = ctx.IsExpression(null, 0, RequestFor.Association); if (res.Result) { var isTableResult = res.Context !.IsExpression(null, 0, RequestFor.Table); if (!isTableResult.Result) { throw new LinqException("Can not retrieve Table context from association."); } var atc = (TableBuilder.TableContext)isTableResult.Context !; deleteStatement.Table = atc.SqlTable; } else { res = ctx.IsExpression(null, 0, RequestFor.Table); if (res.Result && res.Context is TableBuilder.TableContext context) { var tc = context; if (deleteStatement.SelectQuery.From.Tables.Count == 0 || deleteStatement.SelectQuery.From.Tables[0].Source != tc.SelectQuery) { deleteStatement.Table = tc.SqlTable; } } } } var indexedParameters = methodCall.Method.GetParameters().Select((p, i) => Tuple.Create(p, i)).ToDictionary(t => t.Item1.Name, t => t.Item2); Expression GetArgumentByName(string name) { return(methodCall.Arguments[indexedParameters[name]]); } LambdaExpression GetOutputExpression(Type outputType) { if (!indexedParameters.TryGetValue("outputExpression", out var index)) { var param = Expression.Parameter(outputType); return(Expression.Lambda(param, param)); } return((LambdaExpression)methodCall.Arguments[index].Unwrap()); } IBuildContext? outputContext = null; LambdaExpression?outputExpression = null; if (deleteType != DeleteContext.DeleteType.Delete) { outputExpression = GetOutputExpression(methodCall.Method.GetGenericArguments().Last()); deleteStatement.Output = new SqlOutputClause(); var deletedTable = SqlTable.Deleted(methodCall.Method.GetGenericArguments()[0]); outputContext = new TableBuilder.TableContext(builder, new SelectQuery(), deletedTable); deleteStatement.Output.DeletedTable = deletedTable; if (deleteType == DeleteContext.DeleteType.DeleteOutputInto) { var outputTable = GetArgumentByName("outputTable"); var destination = builder.BuildSequence(new BuildInfo(buildInfo, outputTable, new SelectQuery())); UpdateBuilder.BuildSetter( builder, buildInfo, outputExpression, destination, deleteStatement.Output.OutputItems, outputContext); deleteStatement.Output.OutputTable = ((TableBuilder.TableContext)destination).SqlTable; } } if (deleteType == DeleteContext.DeleteType.DeleteOutput) { return(new DeleteWithOutputContext(buildInfo.Parent, sequence, outputContext !, outputExpression !)); } return(new DeleteContext(buildInfo.Parent, sequence)); }
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var mergeContext = (MergeContext)builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); var kind = MergeKind.Merge; if (methodCall.IsSameGenericMethod(MergeWithOutputInto)) { kind = MergeKind.MergeWithOutputInto; } else if (methodCall.IsSameGenericMethod(MergeWithOutput)) { kind = MergeKind.MergeWithOutput; } if (kind != MergeKind.Merge) { var objectType = methodCall.Method.GetGenericArguments()[0]; var actionField = SqlField.FakeField(new DbDataType(typeof(string)), "$action", false); var insertedTable = SqlTable.Inserted(objectType); var deletedTable = SqlTable.Deleted(objectType); mergeContext.Merge.Output = new SqlOutputClause() { InsertedTable = insertedTable, DeletedTable = deletedTable, }; var selectQuery = new SelectQuery(); var actionFieldContext = new SingleExpressionContext(null, builder, actionField, selectQuery); var deletedTableContext = new TableBuilder.TableContext(builder, selectQuery, deletedTable); var insertedTableConext = new TableBuilder.TableContext(builder, selectQuery, insertedTable); if (kind == MergeKind.MergeWithOutput) { var outputExpression = (LambdaExpression)methodCall.Arguments[1].Unwrap(); var outputContext = new MergeOutputContext( buildInfo.Parent, outputExpression, mergeContext, actionFieldContext, deletedTableContext, insertedTableConext ); return(outputContext); } else { var outputExpression = (LambdaExpression)methodCall.Arguments[2].Unwrap(); var outputTable = methodCall.Arguments[1]; var destination = builder.BuildSequence(new BuildInfo(buildInfo, outputTable, new SelectQuery())); UpdateBuilder.BuildSetterWithContext( builder, buildInfo, outputExpression, destination, mergeContext.Merge.Output.OutputItems, actionFieldContext, deletedTableContext, insertedTableConext ); mergeContext.Merge.Output.OutputTable = ((TableBuilder.TableContext)destination).SqlTable; } } return(mergeContext); }