public override void VisitGroupJoinClause(GroupJoinClause groupJoinClause, QueryModel queryModel, int index) { JoinClause joinClause = (JoinClause)groupJoinClause.JoinClause; Type tOuter = queryModel.MainFromClause.ItemType; Type tInner = joinClause.ItemType; Type tOuterKey = joinClause.OuterKeySelector.Type; Type tInnerKey = joinClause.InnerKeySelector.Type; Type tIEnumerableInner = typeof(IEnumerable <>).MakeGenericType(tInner); Type tResult = queryModel.SelectClause.Selector.Type; ParameterExpression iEnumerableInnerParameter = Expression.Parameter(tIEnumerableInner, "d"); ParameterExpression outerParameter = Expression.Parameter(tOuter, "p"); ParameterExpression innerParameter = Expression.Parameter(tInner, "d"); ParameterExpression outerKeyParameter = Expression.Parameter(tOuter, "p"); Expression outerKey = UpdateExpressionVisitor.Update(joinClause.OuterKeySelector, new[] { outerKeyParameter }, dbContext, queryContext); LambdaExpression outerKeyLamda = Expression.Lambda(outerKey, outerKeyParameter); ParameterExpression tInnerKeyParameter = Expression.Parameter(tInner, "d"); Expression innerKey = UpdateExpressionVisitor.Update(joinClause.InnerKeySelector, new[] { tInnerKeyParameter }, dbContext, queryContext); LambdaExpression innerKeyLamda = Expression.Lambda(innerKey, tInnerKeyParameter); Expression selector = UpdateExpressionVisitor.Update(queryModel.SelectClause.Selector, new[] { outerParameter, iEnumerableInnerParameter }, dbContext, queryContext); LambdaExpression selectorLambda = Expression.Lambda(selector, new[] { outerParameter, iEnumerableInnerParameter }); MethodInfo groupJoin = GetMethods("GroupJoin", expression.Type, 4).Where(p => p.GetParameters().Count() == 5).Single(). MakeGenericMethod(new Type[] { tOuter, tInner, tOuterKey, tResult }); expression = Expression.Call(groupJoin, new[] { expression, joinClause.InnerSequence, outerKeyLamda, innerKeyLamda, selectorLambda }); flagsNotVisitSelector = true; }
public override void VisitSelectClause(SelectClause selectClause, QueryModel queryModel) { var genericTypeDefinition = expression.Type.GetGenericArguments(); if (flagsNotVisitSelector || (genericTypeDefinition.Count() == 1 && genericTypeDefinition.First().Equals(selectClause.Selector.Type))) { return; } Type sourceType = genericTypeDefinition.Count() == 1 ? genericTypeDefinition.First() : resultOptionType; MethodInfo selectMethodInfo = typeof(IQueryable).IsAssignableFrom(expression.Type) ? QueryableMethodsHelper.Select : EnumerableMethodsHelper.Select; MemberExpression memberExpression = selectClause.Selector as MemberExpression; if (memberExpression != null) { var parameter = Expression.Parameter(memberExpression.Expression.Type, "p"); memberExpression = (MemberExpression)UpdateExpressionVisitor.Update(memberExpression, new[] { parameter }, dbContext, queryContext); var lambda = Expression.Lambda(memberExpression, parameter); var genericMethodSelect = selectMethodInfo.MakeGenericMethod(memberExpression.Expression.Type, memberExpression.Type); var call = Expression.Call(genericMethodSelect, expression, lambda); expression = call; return; } NewExpression newExpression = selectClause.Selector as NewExpression; if (newExpression != null) { if (sourceType != null) { var parameter = Expression.Parameter(sourceType, "p"); List <Expression> updateArgExp = new List <Expression>(); foreach (var argument in newExpression.Arguments) { var update = UpdateExpressionVisitor.Update(argument, new[] { parameter }, dbContext, queryContext); updateArgExp.Add(update); } Expression newResult = Expression.New(newExpression.Constructor, updateArgExp); var selectGenericMethod = selectMethodInfo.MakeGenericMethod(sourceType, newResult.Type); var lambda = Expression.Lambda(newResult, parameter); var call = Expression.Call(selectGenericMethod, expression, lambda); expression = call; return; } } if (sourceType != null) { var parameter = Expression.Parameter(sourceType, "p"); var update = UpdateExpressionVisitor.Update(selectClause.Selector, new[] { parameter }, dbContext, queryContext); var selectGenericMethod = selectMethodInfo.MakeGenericMethod(sourceType, selectClause.Selector.Type); var lambda = Expression.Lambda(update, parameter); var call = Expression.Call(selectGenericMethod, expression, lambda); expression = call; return; } throw new NotImplementedException(); }
public override void VisitAdditionalFromClause(AdditionalFromClause fromClause, QueryModel queryModel, int index) { Type typeParameter = GetTypeParameter(fromClause.FromExpression); ParameterExpression parameter = Expression.Parameter(typeParameter, "p"); Expression updateExpression = UpdateExpressionVisitor.Update(fromClause.FromExpression, new[] { parameter }, dbContext, queryContext); updateExpression = Expression.Convert(updateExpression, typeof(IEnumerable <>).MakeGenericType(updateExpression.Type.GetGenericArguments())); MethodInfo genericSelectMany = QueryableMethodsHelper.SelectMany.MakeGenericMethod(typeParameter, fromClause.ItemType); LambdaExpression lambda = Expression.Lambda(updateExpression, parameter); MethodCallExpression selectManyResult = Expression.Call(genericSelectMany, new[] { expression, lambda }); expression = selectManyResult; }
public override void VisitWhereClause(WhereClause whereClause, QueryModel queryModel, int index) { ParameterExpression parameterExpression = Expression.Parameter(entityType, "p"); UpdateExpressionVisitor updateExpressionVisitor = new UpdateExpressionVisitor(new[] { parameterExpression }, dbContext, queryContext); Expression predicateUpdate = updateExpressionVisitor.Visit(whereClause.Predicate); if (updateExpressionVisitor.MainParametrExpression != null) { parameterExpression = updateExpressionVisitor.MainParametrExpression; } ; Expression whereLamda = Expression.Lambda(predicateUpdate, parameterExpression); MethodInfo where = GetMethods("Where", expression.Type, 1).First().MakeGenericMethod(entityType); expression = Expression.Call(where, new[] { expression, whereLamda }); }
//public override void VisitOrderByClause(OrderByClause orderByClause, QueryModel queryModel, int index) { // throw new NotSupportedException(); //} public override void VisitOrdering(Ordering ordering, QueryModel queryModel, OrderByClause orderByClause, int index) { ParameterExpression expressionParam = Expression.Parameter(entityType, "p"); Expression updateExpression = UpdateExpressionVisitor.Update(ordering.Expression, new[] { expressionParam }, dbContext, queryContext); LambdaExpression expressionKeyLambda = Expression.Lambda(updateExpression, expressionParam); if (ordering.OrderingDirection == OrderingDirection.Asc) { MethodInfo orderBy = GetMethod("OrderBy", expression.Type, 1).MakeGenericMethod(entityType, ordering.Expression.Type); expression = Expression.Call(orderBy, new[] { expression, expressionKeyLambda }); } else { MethodInfo orderByDescending = GetMethod("OrderByDescending", expression.Type, 1).MakeGenericMethod(entityType, ordering.Expression.Type); expression = Expression.Call(orderByDescending, new[] { expression, expressionKeyLambda }); } }
public override void VisitMainFromClause(MainFromClause fromClause, QueryModel queryModel) { bool processed = false; expression = queryModel.MainFromClause.FromExpression; if (expression is SubQueryExpression) { QueryModel subQueryModel = ((SubQueryExpression)expression).QueryModel; VisitQueryModel(subQueryModel); processed = true; } if (expression is ConstantExpression) { expression = Utility.DbContextHelper.GetDbSet(dbContext, (ConstantExpression)expression); if (BaseSourceExpressionCreated != null) { BaseSourceExpressionCreatedEventArgs eventArgs = new BaseSourceExpressionCreatedEventArgs(expression, queryModel.MainFromClause.ItemType); BaseSourceExpressionCreated(this, eventArgs); expression = eventArgs.Expression; } processed = true; } if (expression is MemberExpression) { QuerySourceReferenceExpression querySourceReferenceExpression = (expression as MemberExpression)?.Expression as QuerySourceReferenceExpression; if (querySourceReferenceExpression != null) { Type paramType = querySourceReferenceExpression.ReferencedQuerySource.ItemType; string paramName = querySourceReferenceExpression.ReferencedQuerySource.ItemName; MainParamerExpression = Expression.Parameter(paramType, paramName); expression = UpdateExpressionVisitor.Update(expression, new[] { MainParamerExpression }, dbContext, queryContext); processed = true; } } if (expression is ParameterExpression) { processed = true; //TODO? } if (!processed) { throw new NotImplementedException(); } entityType = queryModel.MainFromClause.ItemType; selectorType = queryModel.SelectClause.Selector.Type; }
public IQueryCommand <TResult> Select <TResult>(Expression <Func <T, TResult> > predicate) { var visitor = new UpdateExpressionVisitor(); visitor.Visit(predicate); visitor.UpdatedFields.ForEach(t => { _selectField.Append($"{t.Prefix}.{t.ColumnName} as {t.Parameter},"); prefix = t.Prefix; }); _selectField.Remove(_selectField.Length - 1, 1); return(new SimpleQueryable <TResult>(_connection, Build(), _sqlPamater) { Aop = Aop }); }
// 创建 UPDATE 命令 protected override Command ParseUpdateCommand <T>(DbQueryableInfo_Update <T> uQueryInfo, ParserToken token) { ISqlBuilder builder = this.CreateSqlBuilder(token); var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); builder.Append("UPDATE t0 SET"); builder.AppendNewLine(); if (uQueryInfo.Entity != null) { object entity = uQueryInfo.Entity; ISqlBuilder whereBuilder = this.CreateSqlBuilder(token); bool useKey = false; int length = 0; foreach (var kv in typeRuntime.Invokers) { MemberInvokerBase invoker = kv.Value; var column = invoker.Column; if (column != null && column.IsIdentity) { goto gotoLabel; // fix issue# 自增列同时又是主键 } if (column != null && column.NoMapped) { continue; } if (invoker.Column != null && column.DbType is SqlDbType && (SqlDbType)column.DbType == SqlDbType.Timestamp) { continue; // 行版本号 } if (invoker.ForeignKey != null) { continue; } if (invoker.Member.MemberType == System.Reflection.MemberTypes.Method) { continue; } builder.AppendMember("t0", invoker.Member.Name); builder.Append(" = "); gotoLabel: var value = invoker.Invoke(entity); var seg = builder.GetSqlValueWidthDefault(value, column); if (column == null || !column.IsIdentity) { builder.Append(seg); length = builder.Length; builder.Append(','); builder.AppendNewLine(); } if (column != null && column.IsKey) { useKey = true; whereBuilder.AppendMember("t0", invoker.Member.Name); whereBuilder.Append(" = "); whereBuilder.Append(seg); whereBuilder.Append(" AND "); } } if (!useKey) { throw new XFrameworkException("Update<T>(T value) require T must have key column."); } builder.Length = length; whereBuilder.Length -= 5; builder.AppendNewLine(); builder.Append("FROM "); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); builder.Append(" t0"); builder.AppendNewLine(); builder.Append("WHERE "); builder.Append(whereBuilder); } else if (uQueryInfo.Expression != null) { TableAliasCache aliases = this.PrepareAlias <T>(uQueryInfo.SelectInfo, token); ExpressionVisitorBase visitor = null; visitor = new UpdateExpressionVisitor(this, aliases, uQueryInfo.Expression); visitor.Write(builder); builder.AppendNewLine(); builder.Append("FROM "); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); builder.AppendAs("t0"); var cmd2 = new SelectCommand(this, aliases, token) { HasManyNavigation = uQueryInfo.SelectInfo.HasManyNavigation }; visitor = new JoinExpressionVisitor(this, aliases, uQueryInfo.SelectInfo.Joins); visitor.Write(cmd2.JoinFragment); visitor = new WhereExpressionVisitor(this, aliases, uQueryInfo.SelectInfo.WhereExpression); visitor.Write(cmd2.WhereFragment); cmd2.AddNavMembers(visitor.NavMembers); builder.Append(cmd2.CommandText); } return(new Command(builder.ToString(), builder.Token != null ? builder.Token.Parameters : null, System.Data.CommandType.Text)); }
/// <summary> /// 创建 UPDATE 命令 /// </summary> /// <param name="dbQuery">查询语义</param> /// <param name="token">解析上下文</param> /// <returns></returns> protected override RawCommand ResolveUpdateCommand <T>(IDbQueryableInfo_Update dbQuery, ResolveToken token) { var context = (SqlServerDbContext)token.DbContext; ISqlBuilder builder = this.CreateSqlBuilder(token); var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); builder.Append("UPDATE t0 SET"); builder.AppendNewLine(); if (dbQuery.Entity != null) { object entity = dbQuery.Entity; ISqlBuilder seg_Where = this.CreateSqlBuilder(token); bool useKey = false; int length = 0; foreach (var m in typeRuntime.Members) { var column = m.Column; if (column != null && column.IsIdentity) { goto gotoLabel; // Fix issue# 自增列同时又是主键 } if (column != null && column.NoMapped) { continue; } if (m.Column != null && column.DbType is SqlDbType && (SqlDbType)column.DbType == SqlDbType.Timestamp) { continue; // 行版本号 } if (m.ForeignKey != null) { continue; } if (m.Member.MemberType == System.Reflection.MemberTypes.Method) { continue; } builder.AppendMember("t0", m.Member.Name); builder.Append(" = "); gotoLabel: var value = m.Invoke(entity); var seg = this.DbValue.GetSqlValueWidthDefault(value, token, column); if (column == null || !column.IsIdentity) { builder.Append(seg); length = builder.Length; builder.Append(','); builder.AppendNewLine(); } if (column != null && column.IsKey) { useKey = true; seg_Where.AppendMember("t0", m.Member.Name); seg_Where.Append(" = "); seg_Where.Append(seg); seg_Where.Append(" AND "); } } if (!useKey) { throw new XFrameworkException("Update<T>(T value) require entity must have key column."); } builder.Length = length; seg_Where.Length -= 5; builder.AppendNewLine(); builder.Append("FROM "); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); builder.Append(" t0"); builder.AppendNewLine(); builder.Append("WHERE "); builder.Append(seg_Where); } else if (dbQuery.Expression != null) { TableAlias aliases = this.PrepareTableAlias(dbQuery.Query, token); ExpressionVisitorBase visitor = null; visitor = new UpdateExpressionVisitor(this, aliases, dbQuery.Expression); visitor.Write(builder); builder.AppendNewLine(); builder.Append("FROM "); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); builder.AppendAs("t0"); var cmd = new SqlServerMappingCommand(context, aliases, token) { HasMany = dbQuery.Query.HasMany }; visitor = new SqlServerJoinExpressionVisitor(context, aliases, dbQuery.Query.Joins); visitor.Write(cmd.JoinFragment); visitor = new WhereExpressionVisitor(this, aliases, dbQuery.Query.Where); visitor.Write(cmd.WhereFragment); cmd.AddNavMembers(visitor.NavMembers); builder.Append(cmd.CommandText); } return(new RawCommand(builder.ToString(), builder.Token != null ? builder.Token.Parameters : null, System.Data.CommandType.Text)); }
public override void VisitResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, int index) { resultOptionType = resultOptionType ?? queryModel.SelectClause.Selector.Type; if (resultOperator is CastResultOperator) { CastResultOperator castResultOperator = (CastResultOperator)resultOperator; Type castType = castResultOperator.CastItemType; MethodInfo cast = GetMethod("Cast", expression.Type).MakeGenericMethod(castType); resultOptionType = castType; expression = Expression.Call(cast, expression); return; } if (resultOperator is AllResultOperator) { AllResultOperator allResultOperator = (AllResultOperator)resultOperator; ParameterExpression parameterExpression = Expression.Parameter(selectorType, "p"); Expression predicateUpdate = UpdateExpressionVisitor.Update(allResultOperator.Predicate, new[] { parameterExpression }, dbContext, queryContext); Expression allLamda = Expression.Lambda(predicateUpdate, parameterExpression); MethodInfo all = GetMethod("All", expression.Type, 1).MakeGenericMethod(selectorType); expression = Expression.Call(all, new[] { expression, allLamda }); return; } if (resultOperator is FirstResultOperator) { FirstResultOperator firstResultOperator = (FirstResultOperator)resultOperator; if (firstResultOperator.ReturnDefaultWhenEmpty) { MethodInfo firstOrDefault = GetMethod("FirstOrDefault", expression.Type, 0).MakeGenericMethod(selectorType); expression = Expression.Call(firstOrDefault, new[] { expression }); } else { MethodInfo first = GetMethod("First", expression.Type, 0).MakeGenericMethod(selectorType); expression = Expression.Call(first, new[] { expression }); } return; } if (resultOperator is SingleResultOperator) { SingleResultOperator singleResultOperator = (SingleResultOperator)resultOperator; if (singleResultOperator.ReturnDefaultWhenEmpty) { MethodInfo firstOrDefault = GetMethod("SingleOrDefault", expression.Type, 0).MakeGenericMethod(selectorType); expression = Expression.Call(firstOrDefault, new[] { expression }); } else { MethodInfo first = GetMethod("Single", expression.Type, 0).MakeGenericMethod(selectorType); expression = Expression.Call(first, new[] { expression }); } return; } if (resultOperator is AnyResultOperator) { MethodInfo any = GetMethod("Any", expression.Type).MakeGenericMethod(selectorType); expression = Expression.Call(any, new[] { expression }); return; } if (resultOperator is TrackingResultOperator) { MethodInfo asNoTracking = typeof(EntityFrameworkQueryableExtensions).GetMethod("AsNoTracking").MakeGenericMethod(selectorType); expression = Expression.Call(asNoTracking, new[] { expression }); return; } if (resultOperator is CountResultOperator) { MethodInfo count = GetMethod("Count", expression.Type).MakeGenericMethod(selectorType); expression = Expression.Call(count, new[] { expression }); return; } if (resultOperator is AverageResultOperator) { MethodInfo average = GetAgregateMethod("Average", expression.Type, selectorType); expression = Expression.Call(average, new[] { expression }); return; } if (resultOperator is ContainsResultOperator) { ContainsResultOperator containsResultOperator = (ContainsResultOperator)resultOperator; Expression valExp; object value; ParameterExpression paramExp = containsResultOperator.Item as ParameterExpression; if (paramExp != null && queryContext.ParameterValues.TryGetValue(paramExp.Name, out value)) { valExp = Expression.Constant(value); } else { valExp = containsResultOperator.Item; } if (containsResultOperator.Item is SubQueryExpression) { SubQueryExpression subQueryExpression = (SubQueryExpression)containsResultOperator.Item; QueryModelVisitor queryModelVisitor = new QueryModelVisitor(dbContext, queryContext); queryModelVisitor.VisitQueryModel(subQueryExpression.QueryModel); valExp = queryModelVisitor.expression; } MethodInfo contains = GetMethod("Contains", expression.Type, 1).MakeGenericMethod(selectorType); expression = Expression.Call(contains, new[] { expression, valExp }); return; } if (resultOperator is DefaultIfEmptyResultOperator) { DefaultIfEmptyResultOperator defaultIfEmptyResultOperator = (DefaultIfEmptyResultOperator)resultOperator; MethodInfo defaultIfEmpty; if (defaultIfEmptyResultOperator.OptionalDefaultValue != null) { defaultIfEmpty = GetMethod("DefaultIfEmpty", expression.Type, 1).MakeGenericMethod(selectorType); expression = Expression.Call(defaultIfEmpty, new[] { expression, defaultIfEmptyResultOperator.OptionalDefaultValue }); } defaultIfEmpty = GetMethod("DefaultIfEmpty", expression.Type).MakeGenericMethod(selectorType); expression = Expression.Call(defaultIfEmpty, expression); return; } if (resultOperator is DistinctResultOperator) { MethodInfo distinct = GetMethod("Distinct", expression.Type).MakeGenericMethod(selectorType); expression = Expression.Call(distinct, expression); return; } if (resultOperator is GroupResultOperator) { GroupResultOperator groupResultOperator = (GroupResultOperator)resultOperator; Type keySelectorType = GetTypeParameter(groupResultOperator.KeySelector); ParameterExpression keyExpressionParam = Expression.Parameter(keySelectorType, "p"); Expression keyExpression = UpdateExpressionVisitor.Update(groupResultOperator.KeySelector, new[] { keyExpressionParam }, dbContext, queryContext); LambdaExpression keyLambdaExpression = Expression.Lambda(keyExpression, keyExpressionParam); Type elementSelectorType = GetTypeParameter(groupResultOperator.ElementSelector); ParameterExpression ElementExpressionParam = Expression.Parameter(elementSelectorType, "p"); Expression ElementExpression = UpdateExpressionVisitor.Update(groupResultOperator.ElementSelector, new[] { ElementExpressionParam }, dbContext, queryContext); LambdaExpression ElementLambdaExpression = Expression.Lambda(ElementExpression, ElementExpressionParam); Type tSource = queryModel.MainFromClause.ItemType; Type tKey = keyExpression.Type; Type tElement = ElementExpression.Type; Type tResult = queryModel.ResultTypeOverride; MethodInfo groupBy = GetMethods("GroupBy", expression.Type, 2).Where(p => p.GetParameters()[2].Name == "elementSelector").Single(). MakeGenericMethod(tSource, tKey, tElement); expression = Expression.Call(groupBy, new[] { expression, keyLambdaExpression, ElementLambdaExpression }); return; } if (resultOperator is LastResultOperator) { LastResultOperator lastResultOperator = (LastResultOperator)resultOperator; if (lastResultOperator.ReturnDefaultWhenEmpty) { MethodInfo lastOrDefault = GetMethod("LastOrDefault", expression.Type, 0).MakeGenericMethod(selectorType); expression = Expression.Call(lastOrDefault, new[] { expression }); } else { MethodInfo last = GetMethod("Last", expression.Type, 0).MakeGenericMethod(selectorType); expression = Expression.Call(last, new[] { expression }); } return; } if (resultOperator is LongCountResultOperator) { MethodInfo longCount = GetMethod("LongCount", expression.Type).MakeGenericMethod(selectorType); expression = Expression.Call(longCount, new[] { expression }); return; } if (resultOperator is MaxResultOperator) { MethodInfo max = GetMethod("Max", expression.Type).MakeGenericMethod(selectorType); expression = Expression.Call(max, expression); return; } if (resultOperator is MinResultOperator) { MethodInfo min = GetMethod("Min", expression.Type).MakeGenericMethod(selectorType); expression = Expression.Call(min, expression); return; } if (resultOperator is SumResultOperator) { MethodInfo sum = GetAgregateMethod("Sum", expression.Type, selectorType); expression = Expression.Call(sum, expression); return; } if (resultOperator is SkipResultOperator) { SkipResultOperator skipResultOperator = (SkipResultOperator)resultOperator; Expression expVal; object value; ParameterExpression paramExp = skipResultOperator.Count as ParameterExpression; if (paramExp != null && queryContext.ParameterValues.TryGetValue(paramExp.Name, out value)) { expVal = Expression.Constant(value); } else { expVal = skipResultOperator.Count; } MethodInfo skip = GetMethod("Skip", expression.Type, 1).MakeGenericMethod(selectorType); expression = Expression.Call(skip, new[] { expression, expVal }); return; } if (resultOperator is TakeResultOperator) { TakeResultOperator takeResultOperator = (TakeResultOperator)resultOperator; Expression expVal; object value; ParameterExpression paramExp = takeResultOperator.Count as ParameterExpression; if (paramExp != null && queryContext.ParameterValues.TryGetValue(paramExp.Name, out value)) { expVal = Expression.Constant(value); } else { expVal = takeResultOperator.Count; } MethodInfo take = GetMethod("Take", expression.Type, 1).MakeGenericMethod(selectorType); expression = Expression.Call(take, new[] { expression, expVal }); return; } if (resultOperator is IncludeResultOperator) { IncludeResultOperator includeResultOperator = (IncludeResultOperator)resultOperator; Expression includeExpression = includeResultOperator.NavigationPropertyPath; Type paramExpressionType = null; ParameterExpression parameterExpression = null; if (includeExpression is MemberExpression) { MemberExpression memberExpression = (MemberExpression)includeExpression; paramExpressionType = memberExpression.Expression.Type; parameterExpression = Expression.Parameter(paramExpressionType, "p"); includeExpression = Expression.Property(parameterExpression, memberExpression.Member.Name); } else { paramExpressionType = GetTypeParameter(includeExpression); parameterExpression = Expression.Parameter(paramExpressionType, "p"); } Expression updateOuterExpression = UpdateExpressionVisitor.Update(includeExpression, new[] { parameterExpression }, dbContext, queryContext); LambdaExpression lambdaIncludeExpression = Expression.Lambda(updateOuterExpression, parameterExpression); MethodInfo include = typeof(EntityFrameworkQueryableExtensions).GetMethods().First(m => m.Name == "Include").MakeGenericMethod(selectorType, updateOuterExpression.Type); expression = Expression.Call(include, new[] { expression, lambdaIncludeExpression }); if (includeResultOperator.ChainedNavigationProperties != null) { foreach (PropertyInfo propertyInfo in includeResultOperator.ChainedNavigationProperties) { Type propertyType = propertyInfo.PropertyType; Type argument = expression.Type.GetGenericArguments().Last(); MethodInfo thenInclude; Type realType; if (typeof(IEnumerable).IsAssignableFrom(argument)) { realType = argument.GetGenericArguments().First(); thenInclude = ThenIncludeCollection.MakeGenericMethod(includeResultOperator.QuerySource.ItemType, realType, propertyType); } else { realType = argument; thenInclude = ThenIncludeProperty.MakeGenericMethod(includeResultOperator.QuerySource.ItemType, realType, propertyType); } ParameterExpression parameterThenIncludeExpression = Expression.Parameter(realType, "p"); MemberExpression property = Expression.Property(parameterThenIncludeExpression, propertyInfo); LambdaExpression lambdaThenIncludeExpression = Expression.Lambda(property, parameterThenIncludeExpression); expression = Expression.Call(thenInclude, new[] { expression, lambdaThenIncludeExpression }); } } return; } if (resultOperator is OfTypeResultOperator) { OfTypeResultOperator ofTypeResultOperator = (OfTypeResultOperator)resultOperator; selectorType = ofTypeResultOperator.SearchedItemType; var miOfType = GetMethod("OfType", expression.Type).MakeGenericMethod(ofTypeResultOperator.SearchedItemType); expression = Expression.Call(miOfType, new[] { expression }); return; } throw new NotSupportedException(); }
/// <summary> /// 创建 UPDATE 命令 /// </summary> /// <param name="dbQuery">查询语义</param> /// <param name="token">解析上下文</param> /// <returns></returns> protected override RawCommand ResolveUpdateCommand <T>(IDbQueryableInfo_Update dbQuery, ResolveToken token) { ISqlBuilder builder = this.CreateSqlBuilder(token); var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); builder.Append("UPDATE "); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); builder.Append(" t0 SET"); builder.AppendNewLine(); if (dbQuery.Entity != null) { object entity = dbQuery.Entity; ISqlBuilder seg_Where = this.CreateSqlBuilder(token); bool useKey = false; int length = 0; foreach (var m in typeRuntime.Members) { var column = m.Column; if (column != null && column.IsIdentity) { goto gotoLabel; // Fix issue# 自增列同时又是主键 } if (column != null && column.NoMapped) { continue; } if (m.ForeignKey != null) { continue; } if (m.Member.MemberType == System.Reflection.MemberTypes.Method) { continue; } builder.AppendMember(m.Member.Name); builder.Append(" = "); gotoLabel: if (column == null || !column.IsIdentity) { var value = m.Invoke(entity); var seg = this.DbValue.GetSqlValueWidthDefault(value, token, column); builder.Append(seg); length = builder.Length; builder.Append(','); builder.AppendNewLine(); } if (column != null && column.IsKey) { useKey = true; } } if (!useKey) { throw new XFrameworkException("Update<T>(T value) require T must have key column."); } // ORACLE 需要注意参数顺序问题 int index = -1; foreach (var m in typeRuntime.KeyMembers) { var column = m.Column; var value = m.Invoke(entity); var seg = this.DbValue.GetSqlValueWidthDefault(value, token, column); index += 1; seg_Where.AppendMember(m.Member.Name); seg_Where.Append(" = "); seg_Where.Append(seg); if (index < typeRuntime.KeyMembers.Count - 1) { seg_Where.Append(" AND "); } } builder.Length = length; builder.AppendNewLine(); builder.Append("WHERE "); builder.Append(seg_Where); } else if (dbQuery.Expression != null) { // SELECT 表达式 LambdaExpression lambda = dbQuery.Expression as LambdaExpression; var body = lambda.Body; Expression expression = null; if (body.NodeType == ExpressionType.MemberInit) { var @init = body as MemberInitExpression; var bindings = new List <MemberBinding>(@init.Bindings); foreach (var m in typeRuntime.KeyMembers) { var member = Expression.MakeMemberAccess(lambda.Parameters[0], m.Member); var binding = Expression.Bind(m.Member, member); if (!bindings.Any(x => x.Member == m.Member)) { bindings.Add(binding); } } expression = Expression.MemberInit(@init.NewExpression, bindings); } else if (body.NodeType == ExpressionType.New) { var newExpression = body as NewExpression; var bindings = new List <MemberBinding>(); for (int i = 0; i < newExpression.Members.Count; i++) { var m = typeRuntime.GetMember(newExpression.Members[i].Name); var binding = Expression.Bind(m.Member, newExpression.Arguments[i].Type != m.DataType ? Expression.Convert(newExpression.Arguments[i], m.DataType) : newExpression.Arguments[i]); bindings.Add(binding); } foreach (var m in typeRuntime.KeyMembers) { var member = Expression.MakeMemberAccess(lambda.Parameters[0], m.Member); var binding = Expression.Bind(m.Member, member); if (!bindings.Any(x => x.Member == m.Member)) { bindings.Add(binding); } } var newExpression2 = Expression.New(typeRuntime.Constructor.Constructor); expression = Expression.MemberInit(newExpression2, bindings); } // 解析查询以确定是否需要嵌套 dbQuery.Query.Select = new DbExpression(DbExpressionType.Select, expression); var cmd = (MappingCommand)this.ResolveSelectCommand(dbQuery.Query, 1, false, null);//, token); if ((cmd.NavMembers != null && cmd.NavMembers.Count > 0) || dbQuery.Query.Joins.Count > 0) { // 无法使用 DISTINCT, GROUP BY 等子句从视图中选择 ROWID 或采样。UPDATE 不能用rowid // 有导航属性或者关联查询,使用 MERGE INTO 语法。要求必须有主键 if (typeRuntime.KeyMembers == null || typeRuntime.KeyMembers.Count == 0) { throw new XFrameworkException("Update<T>(Expression<Func<T, object>> updateExpression) require entity must have key column."); } builder.Length = 0; builder.Append("MERGE INTO "); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); builder.AppendNewLine(" t0"); builder.Append("USING ("); cmd = (MappingCommand)this.ResolveSelectCommand(dbQuery.Query, 1, false, token); builder.AppendNewLine(cmd.CommandText); builder.Append(") t1 ON ("); foreach (var m in typeRuntime.KeyMembers) { builder.AppendMember("t0", m.Name); builder.Append(" = "); builder.AppendMember("t1", m.Name); builder.Append(" AND "); } builder.Length -= 5; builder.Append(')'); // UPDATE builder.AppendNewLine(); builder.AppendNewLine("WHEN MATCHED THEN UPDATE SET "); // SET 字段 var visitor = new OracleUpdateExpressionVisitor(this, null, dbQuery.Expression); visitor.Write(builder); } else { // 直接 SQL 的 UPDATE 语法 TableAlias aliases = this.PrepareTableAlias(dbQuery.Query, token); var visitor = new UpdateExpressionVisitor(this, aliases, dbQuery.Expression); visitor.Write(builder); var visitor_ = new WhereExpressionVisitor(this, aliases, dbQuery.Query.Where); visitor_.Write(builder); } } builder.Append(';'); return(new RawCommand(builder.ToString(), builder.Token != null ? builder.Token.Parameters : null, System.Data.CommandType.Text)); }
/// <summary> /// 创建 UPDATE 命令 /// </summary> /// <param name="tree">查询语义</param> /// <param name="context">解析SQL命令上下文</param> /// <returns></returns> protected override DbRawCommand TranslateUpdateCommand <T>(DbQueryUpdateTree tree, ITranslateContext context) { ISqlBuilder builder = this.CreateSqlBuilder(context); var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); builder.Append("UPDATE "); builder.AppendTable(typeRuntime.TableSchema, typeRuntime.TableName, typeRuntime.IsTemporary); builder.Append(" t0"); if (tree.Entity != null) { object entity = tree.Entity; ISqlBuilder whereBuilder = this.CreateSqlBuilder(context); bool useKey = false; int length = 0; builder.AppendNewLine(" SET"); foreach (var item in typeRuntime.Members) { var m = item as FieldAccessorBase; if (m == null || !m.IsDbField) { continue; } if (m.Column != null && m.Column.IsIdentity) { goto LABEL; // Fix issue# 自增列同时又是主键 } builder.AppendMember("t0", m.Member, typeRuntime.Type); builder.Append(" = "); LABEL: var value = m.Invoke(entity); var seg = this.Constor.GetSqlValueWidthDefault(value, context, m.Column); if (m.Column == null || !m.Column.IsIdentity) { builder.Append(seg); length = builder.Length; builder.Append(','); builder.AppendNewLine(); } if (m.Column != null && m.Column.IsKey) { useKey = true; whereBuilder.AppendMember("t0", m.Member, typeRuntime.Type); whereBuilder.Append(" = "); whereBuilder.Append(seg); whereBuilder.Append(" AND "); } } if (!useKey) { throw new XFrameworkException("Update<T>(T value) require T must have key column."); } builder.Length = length; whereBuilder.Length -= 5; builder.AppendNewLine(); builder.Append("WHERE "); builder.Append(whereBuilder); } else if (tree.Expression != null) { AliasGenerator ag = this.PrepareTableAlias(tree.Select, context.AliasPrefix); DbExpressionVisitor visitor = null; var cmd = new DbSelectCommand(context, ag, tree.Select.SelectHasMany); if (tree.Select.Joins != null) { visitor = new JoinExpressionVisitor(ag, cmd.JoinFragment); visitor.Visit(tree.Select.Joins); } cmd.WhereFragment.AppendNewLine(); cmd.WhereFragment.AppendNewLine("SET"); visitor = new UpdateExpressionVisitor(ag, cmd.WhereFragment); visitor.Visit(tree.Expression); if (tree.Select.Wheres != null) { visitor = new WhereExpressionVisitor(ag, cmd.WhereFragment); visitor.Visit(tree.Select.Wheres); cmd.AddNavMembers(visitor.NavMembers); } builder.Append(cmd.CommandText); } builder.Append(';'); return(new DbRawCommand(builder.ToString(), builder.TranslateContext != null ? builder.TranslateContext.Parameters : null, System.Data.CommandType.Text)); }
// 创建 UPDATE 命令 protected override CommandDefine ParseUpdateCommand <T>(DbQueryableInfo_Update <T> qUpdate) { SqlBuilder builder = new SqlBuilder(this.EscCharLeft, this.EscCharRight); var rInfo = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); builder.Append("UPDATE t0 SET"); builder.AppendNewLine(); if (qUpdate.Entity != null) { object entity = qUpdate.Entity; SqlBuilder whereBuilder = new SqlBuilder(this.EscCharLeft, this.EscCharRight); bool useKey = false; int length = 0; foreach (var kv in rInfo.Wrappers) { var wrapper = kv.Value as MemberAccessWrapper; var column = wrapper.Column; if (column != null && column.IsIdentity) { continue; } if (column != null && column.NoMapped) { continue; } if (wrapper.ForeignKey != null) { continue; } builder.AppendMember("t0", wrapper.Member.Name); builder.Append(" = "); var value = wrapper.Get(entity); var seg = ExpressionVisitorBase.GetSqlValue(value); builder.Append(seg); length = builder.Length; builder.Append(','); builder.AppendNewLine(); if (column != null && column.IsKey) { useKey = true; whereBuilder.AppendMember("t0", wrapper.Member.Name); whereBuilder.Append(" = "); whereBuilder.Append(seg); whereBuilder.Append(" AND "); } } if (!useKey) { throw new XfwException("Update<T>(T value) require T must have key column."); } builder.Length = length; whereBuilder.Length -= 5; builder.AppendNewLine(); builder.Append("FROM "); builder.AppendMember(rInfo.TableName); builder.Append(" t0"); builder.AppendNewLine(); builder.Append("WHERE "); builder.Append(whereBuilder); } else if (qUpdate.Expression != null) { TableAliasCache aliases = this.PrepareAlias <T>(qUpdate.SelectInfo); ExpressionVisitorBase visitor = null; visitor = new UpdateExpressionVisitor(this, aliases, qUpdate.Expression); visitor.Write(builder); builder.AppendNewLine(); builder.Append("FROM "); builder.AppendMember(rInfo.TableName); builder.AppendAs("t0"); var sc = new CommandDefine_Select.Builder(this.EscCharLeft, this.EscCharRight, aliases); visitor = new JoinExpressionVisitor(this, aliases, qUpdate.SelectInfo.Join); visitor.Write(sc.JoinFragment); visitor = new WhereExpressionVisitor(this, aliases, qUpdate.SelectInfo.Where); visitor.Write(sc.WhereFragment); sc.AddNavigation(visitor.Navigations); builder.Append(sc.Command); } return(new CommandDefine(builder.ToString(), null, System.Data.CommandType.Text)); //builder.ToString(); }
/// <summary> /// 创建 UPDATE 命令 /// </summary> /// <param name="tree">查询语义</param> /// <param name="context">解析SQL命令上下文</param> /// <returns></returns> protected override DbRawCommand TranslateUpdateCommand <T>(DbQueryUpdateTree tree, ITranslateContext context) { ISqlBuilder builder = this.CreateSqlBuilder(context); var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); builder.Append("UPDATE "); builder.AppendTable(typeRuntime.TableSchema, typeRuntime.TableName, typeRuntime.IsTemporary); builder.Append(" t0 SET"); builder.AppendNewLine(); if (tree.Entity != null) { object entity = tree.Entity; ISqlBuilder whereBuilder = this.CreateSqlBuilder(context); bool useKey = false; int length = 0; foreach (var item in typeRuntime.Members) { var m = item as FieldAccessorBase; if (m == null || !m.IsDbField) { continue; } if (m.Column != null && m.Column.IsIdentity) { goto LABEL; // Fix issue# 自增列同时又是主键 } builder.AppendMember(null, m.Member, typeRuntime.Type); builder.Append(" = "); LABEL: if (m.Column == null || !m.Column.IsIdentity) { var value = m.Invoke(entity); var sqlExpression = this.Constor.GetSqlValueWidthDefault(value, context, m.Column); builder.Append(sqlExpression); length = builder.Length; builder.Append(','); builder.AppendNewLine(); } if (m.Column != null && m.Column.IsKey) { useKey = true; } } if (!useKey) { throw new XFrameworkException("Update<T>(T value) require T must have key column."); } // ORACLE 需要注意参数顺序问题 int index = -1; foreach (FieldAccessorBase m in typeRuntime.KeyMembers) { var column = m.Column; var value = m.Invoke(entity); var seg = this.Constor.GetSqlValueWidthDefault(value, context, column); index += 1; whereBuilder.AppendMember(null, m.Member, typeRuntime.Type); whereBuilder.Append(" = "); whereBuilder.Append(seg); if (index < typeRuntime.KeyMembers.Count - 1) { whereBuilder.Append(" AND "); } } builder.Length = length; builder.AppendNewLine(); builder.Append("WHERE "); builder.Append(whereBuilder); } else if (tree.Expression != null) { // SELECT 表达式 LambdaExpression lambda = tree.Expression as LambdaExpression; var body = lambda.Body; Expression expression = null; if (body.NodeType == ExpressionType.MemberInit) { var initExpression = body as MemberInitExpression; var bindings = new List <MemberBinding>(initExpression.Bindings); foreach (var m in typeRuntime.KeyMembers) { var member = Expression.MakeMemberAccess(lambda.Parameters[0], m.Member); var binding = Expression.Bind(m.Member, member); if (!bindings.Any(x => x.Member == m.Member)) { bindings.Add(binding); } } expression = Expression.MemberInit(initExpression.NewExpression, bindings); } else if (body.NodeType == ExpressionType.New) { var newExpression = body as NewExpression; var bindings = new List <MemberBinding>(); for (int index = 0; index < newExpression.Members.Count; index++) { var m = (FieldAccessorBase)typeRuntime.Members.FirstOrDefault(a => a is FieldAccessorBase && ( a.Name == newExpression.Members[index].Name || ((FieldAccessorBase)a).Column != null && ((FieldAccessorBase)a).Column.Name == newExpression.Members[index].Name)); if (m == null) { throw new XFrameworkException("Member {0}.{1} not found.", typeRuntime.Type.Name, newExpression.Members[index].Name); } var binding = Expression.Bind(m.Member, newExpression.Arguments[index].Type != m.CLRType ? Expression.Convert(newExpression.Arguments[index], m.CLRType) : newExpression.Arguments[index]); bindings.Add(binding); } foreach (var m in typeRuntime.KeyMembers) { var member = Expression.MakeMemberAccess(lambda.Parameters[0], m.Member); var binding = Expression.Bind(m.Member, member); if (!bindings.Any(x => x.Member == m.Member)) { bindings.Add(binding); } } var newExpression2 = Expression.New(typeRuntime.Constructor.Member); expression = Expression.MemberInit(newExpression2, bindings); } // 解析查询以确定是否需要嵌套 tree.Select.Select = new DbExpression(DbExpressionType.Select, expression); var cmd = (DbSelectCommand)this.TranslateSelectCommand(tree.Select, 0, false, this.CreateTranslateContext(context.DbContext)); if ((cmd.NavMembers != null && cmd.NavMembers.Count > 0) || (tree.Select.Joins != null && tree.Select.Joins.Count > 0)) { // 无法使用 DISTINCT, GROUP BY 等子句从视图中选择 ROWID 或采样。UPDATE 不能用rowid // 有导航属性或者关联查询,使用 MERGE INTO 语法。要求必须有主键 if (typeRuntime.KeyMembers == null || typeRuntime.KeyMembers.Count == 0) { throw new XFrameworkException("Update<T>(Expression<Func<T, object>> updateExpression) require entity must have key column."); } builder.Length = 0; builder.Append("MERGE INTO "); builder.AppendTable(typeRuntime.TableSchema, typeRuntime.TableName, typeRuntime.IsTemporary); builder.AppendNewLine(" t0"); builder.Append("USING ("); cmd = (DbSelectCommand)this.TranslateSelectCommand(tree.Select, 1, false, context); builder.AppendNewLine(cmd.CommandText); builder.Append(") t1 ON ("); foreach (var m in typeRuntime.KeyMembers) { builder.AppendMember("t0", m.Member, typeRuntime.Type); builder.Append(" = "); builder.AppendMember("t1", m.Member, typeRuntime.Type); builder.Append(" AND "); } builder.Length -= 5; builder.Append(')'); // UPDATE builder.AppendNewLine(); builder.AppendNewLine("WHEN MATCHED THEN UPDATE SET "); // SET 字段 var visitor = new OracleUpdateExpressionVisitor(null, builder); visitor.Visit(tree.Expression); } else { // 直接 SQL 的 UPDATE 语法 DbExpressionVisitor visitor = null; AliasGenerator ag = this.PrepareTableAlias(tree.Select, context.AliasPrefix); visitor = new UpdateExpressionVisitor(ag, builder); visitor.Visit(tree.Expression); if (tree.Select.Wheres != null) { visitor = new WhereExpressionVisitor(ag, builder); visitor.Visit(tree.Select.Wheres); } } } builder.Append(';'); return(new DbRawCommand(builder.ToString(), builder.TranslateContext != null ? builder.TranslateContext.Parameters : null, System.Data.CommandType.Text)); }