//p=>p //p=>p.t //p=>p.Id protected override Expression VisitLambda <T>(Expression <T> node) { LambdaExpression lambda = node as LambdaExpression; if (lambda.Body.NodeType == ExpressionType.Parameter) { // expression like a=> a Type type = lambda.Body.Type; string alias = _aliases.GetTableAlias(lambda); this.VisitAllMember(type, alias); return(node); } if (lambda.Body.NodeType == ExpressionType.MemberAccess) { // expression like t=> t.a // => SELECT a.ClientId Type type = lambda.Body.Type; return(TypeUtils.IsPrimitive(type) ? base.VisitLambda(node) : this.VisitAllMember(type, _aliases.GetTableAlias(lambda.Body), node)); } if (_mOnly) { _mOnly = false; } return(base.VisitLambda(node)); }
// 获取 LEFT JOIN / INNER JOIN 子句关联表的的别名 private void GetLfInJoinAlias(DbExpression exp, TableAliasCache aliases) { Type type = exp.Expressions[0].Type.GetGenericArguments()[0]; string name = TypeRuntimeInfoCache.GetRuntimeInfo(type).TableName; // on a.Name equals b.Name 或 on new{ Name = a.Name,Id=a.Id } equals new { Name = b.Name,Id=b.Id } LambdaExpression left = exp.Expressions[1] as LambdaExpression; LambdaExpression right = exp.Expressions[2] as LambdaExpression; NewExpression body1 = left.Body as NewExpression; if (body1 == null) { aliases.GetTableAlias(exp.Expressions[1]); string alias = aliases.GetTableAlias(exp.Expressions[2]); // 记录显示指定的LEFT JOIN 表别名 aliases.AddOrUpdateJoinTableAlias(name, alias); } else { NewExpression body2 = right.Body as NewExpression; for (int index = 0; index < body1.Arguments.Count; ++index) { aliases.GetTableAlias(body1.Arguments[index]); string alias = aliases.GetTableAlias(body2.Arguments[index]); // 记录显示指定的LEFT JOIN 表别名 aliases.AddOrUpdateJoinTableAlias(name, alias); } } }
// LEFT OR INNER JOIN private void AppendLfInJoin(SqlBuilder builder, DbExpression exp, TableAliasCache aliases) { // [TableName] //var constExp = exp.Expressions[0] as ConstantExpression; //constExp.Type.GetGenericArguments()[0] //var queryable = constExp.Value as IDbQueryable; //var innerExp = queryable.DbExpressions[0]; //if (innerExp.DbExpressionType != DbExpressionType.GetTable) throw new XfwException("inner expression must be GetTable<T> expression"); //Type type = (innerExp.Expression as ConstantExpression).Value as Type; Type type = exp.Expressions[0].Type.GetGenericArguments()[0]; builder.Append(' '); builder.AppendMember(TypeRuntimeInfoCache.GetRuntimeInfo(type).TableName); LambdaExpression left = exp.Expressions[1] as LambdaExpression; LambdaExpression right = exp.Expressions[2] as LambdaExpression; NewExpression body1 = left.Body as NewExpression; NewExpression body2 = right.Body as NewExpression; // t0(t1) string alias = body1 == null ? aliases.GetTableAlias(exp.Expressions[2]) : aliases.GetTableAlias(body2.Arguments[0]); builder.Append(' '); builder.Append(alias); builder.Append(' '); // ON a.Name = b.Name AND a.Id = b.Id builder.Append("ON "); if (body1 == null) { builder.AppendMember(aliases, left.Body.ReduceUnary()); builder.Append(" = "); builder.AppendMember(aliases, right.Body.ReduceUnary()); } else { for (int index = 0; index < body1.Arguments.Count; ++index) { builder.AppendMember(aliases, body1.Arguments[index]); builder.Append(" = "); builder.AppendMember(aliases, body2.Arguments[index]); if (index < body1.Arguments.Count - 1) { builder.Append(" AND "); } } } }
/// <summary> /// 追加列名 /// </summary> /// <param name="aliases">表别名</param> /// <param name="expression">列名表达式</param> /// <returns>返回解析到的表别名</returns> public string AppendMember(TableAliasCache aliases, Expression expression) { Expression exp = expression; LambdaExpression lambdaExpression = exp as LambdaExpression; if (lambdaExpression != null) { exp = lambdaExpression.Body; } MemberExpression memExp = exp as MemberExpression; if (expression.NodeType == ExpressionType.Constant || memExp.Expression.NodeType == ExpressionType.Constant) { PartialVisitor visitor = new PartialVisitor(); var eval = visitor.Eval(memExp ?? expression); string value = eval.NodeType == ExpressionType.Constant ? ExpressionVisitorBase.GetSqlValue((eval as ConstantExpression).Value) : string.Empty; _builder.Append(value); return(value); } else { string alias = aliases == null ? null : aliases.GetTableAlias(memExp); this.AppendMember(alias, memExp.Member.Name); return(alias); } }
// 获取 CROSS JOIN 子句关联表的的别名 private void GetCrossJoinAlias(DbExpression exp, TableAliasCache aliases) { LambdaExpression lambdaExp = exp.Expressions[1] as LambdaExpression; for (int index = 0; index < lambdaExp.Parameters.Count; ++index) { aliases.GetTableAlias(lambdaExp.Parameters[index]); } }
// Cross Join private void AppendCrossJoin(SqlBuilder builder, DbExpression exp, TableAliasCache aliases) { LambdaExpression lambdaExp = exp.Expressions[1] as LambdaExpression; Type type = lambdaExp.Parameters[1].Type; builder.Append(' '); builder.AppendMember(TypeRuntimeInfoCache.GetRuntimeInfo(type).TableName); string alias = aliases.GetTableAlias(lambdaExp.Parameters[1]); builder.Append(' '); builder.Append(alias); builder.Append(' '); }
protected virtual void VisitNavigation(Expression node, string memberName = null) { // 表达式 => b.Client.Address.AddressName Expression f = node; Stack <KeyValuePair <string, MemberExpression> > stack = null; while (f != null && f.IsVisitable()) { if (f.NodeType != ExpressionType.MemberAccess) { break; } if (stack == null) { stack = new Stack <KeyValuePair <string, MemberExpression> >(); } MemberExpression m = f as MemberExpression; var runtime = TypeRuntimeInfoCache.GetRuntimeInfo(m.Expression.Type); ForeignKeyAttribute attribute = runtime.GetWrapperAttribute <ForeignKeyAttribute>(m.Member.Name); if (attribute == null) { break; } string key = m.GetKeyWidthoutAnonymous(); stack.Push(new KeyValuePair <string, MemberExpression>(key, m)); f = m.Expression; } if (stack != null && stack.Count > 0) { while (stack != null && stack.Count > 0) { KeyValuePair <string, MemberExpression> kvp = stack.Pop(); string key = kvp.Key; MemberExpression m = kvp.Value; var runtime = TypeRuntimeInfoCache.GetRuntimeInfo(m.Type); // 检查查询表达式是否显示指定该表关联 string alias = _aliases.GetJoinTableAlias(runtime.TableName); if (string.IsNullOrEmpty(alias)) { // 如果没有,则使用导航属性别名 alias = _aliases.GetNavigationTableAlias(key); if (!_navigations.ContainsKey(kvp.Key)) { _navigations.Add(kvp); } } if (stack.Count == 0 && !string.IsNullOrEmpty(memberName)) { _builder.AppendMember(alias, memberName); } } } else { // => SelectMany 也会产生类似 'b.Client.Address.AddressName' 这样的表达式 string alias = _aliases.GetTableAlias(node); _builder.AppendMember(alias, memberName); } //return f; }
// 添加导航属性关联 protected virtual void AppendNavigation() { if (this.AdditionForeigns == null || this.AdditionForeigns.Count == 0) { return; } //开始产生LEFT JOIN 子句 SqlBuilder builder = this.JoinFragment; foreach (var kvp in _navigations) { string key = kvp.Key; MemberExpression m = kvp.Value; var runtime = TypeRuntimeInfoCache.GetRuntimeInfo(m.Expression.Type); ForeignKeyAttribute attribute = runtime.GetWrapperAttribute <ForeignKeyAttribute>(m.Member.Name); string innerKey = string.Empty; string outerKey = key; string innerAlias = string.Empty; if (!m.Expression.IsVisitable()) { innerKey = m.Expression.NodeType == ExpressionType.Parameter ? (m.Expression as ParameterExpression).Name : (m.Expression as MemberExpression).Member.Name; } else { MemberExpression mLeft = m.Expression as MemberExpression; string name = TypeRuntimeInfoCache.GetRuntimeInfo(mLeft.Type).TableName; innerAlias = _aliases.GetJoinTableAlias(name); if (string.IsNullOrEmpty(innerAlias)) { string keyLeft = mLeft.GetKeyWidthoutAnonymous(); if (_navigations.ContainsKey(keyLeft)) { innerKey = keyLeft; } } } string alias1 = !string.IsNullOrEmpty(innerAlias) ? innerAlias : _aliases.GetTableAlias(innerKey); string alias2 = _aliases.GetTableAlias(outerKey); builder.AppendNewLine(); builder.Append("LEFT JOIN "); Type pType = m.Type; //不实现一对多映射 //if (pType.IsGenericType) pType = pType.GetGenericArguments()[0]; builder.AppendMember(TypeRuntimeInfoCache.GetRuntimeInfo(pType).TableName); builder.Append(" "); builder.Append(alias2); builder.Append(" ON "); for (int i = 0; i < attribute.InnerKeys.Length; i++) { builder.Append(alias1); builder.Append('.'); builder.AppendMember(attribute.InnerKeys[i]); builder.Append(" = "); builder.Append(alias2); builder.Append('.'); builder.AppendMember(attribute.OuterKeys[i]); if (i < attribute.InnerKeys.Length - 1) { builder.Append(" AND "); } } } }