// 构造由一对多关系产生的嵌套查询 static DbQueryableInfo_Select <TElement> TryBuilOuter <TElement>(DbQueryableInfo_Select <TElement> sQuery) { if (sQuery == null || sQuery.Select == null) { return(sQuery); } Expression select = sQuery.Select.Expressions[0]; List <DbExpression> include = sQuery.Include; Type type = sQuery.FromType; // 解析导航属性 如果有 一对多 的导航属性,那么查询的结果集的主记录将会有重复记录,这时就需要使用嵌套语义,先查主记录,再关联导航记录 bool checkListNavgation = false; Expression expression = select; LambdaExpression lambdaExpression = expression as LambdaExpression; if (lambdaExpression != null) { expression = lambdaExpression.Body; } MemberInitExpression initExpression = expression as MemberInitExpression; NewExpression newExpression = expression as NewExpression; foreach (DbExpression d in include) { Expression exp = d.Expressions[0]; if (exp.NodeType == ExpressionType.Lambda) { exp = (exp as LambdaExpression).Body; } else if (exp.NodeType == ExpressionType.Call) { exp = (exp as MethodCallExpression).Object; } // Include 如果包含List<>泛型导航,则可以判定整个查询包含一对多的导航 //if (exp.Type.IsGenericType && exp.Type.GetGenericTypeDefinition() == typeof(List<>)) checkListNavgation = true; if (TypeUtils.IsCollectionType(exp.Type)) { checkListNavgation = true; } if (checkListNavgation) { break; } } if (!checkListNavgation) { checkListNavgation = initExpression != null && CheckListNavigation <TElement>(initExpression); } if (checkListNavgation) { newExpression = initExpression != null ? initExpression.NewExpression : newExpression; List <MemberBinding> bindings = new List <MemberBinding>(); if (initExpression != null) { bindings = initExpression.Bindings.ToList(x => x, x => TypeUtils.IsPrimitiveType((x.Member as System.Reflection.PropertyInfo).PropertyType)); } if (newExpression != null || bindings.Count() > 0) { // 简化内层选择器,只选择最小字段,不选择导航字段,导航字段在外层加进去 initExpression = Expression.MemberInit(newExpression, bindings); lambdaExpression = Expression.Lambda(initExpression, lambdaExpression.Parameters); sQuery.Select = new DbExpression(DbExpressionType.Select, lambdaExpression); } sQuery.GenByListNavigation = true; sQuery.Include = new List <DbExpression>(); var outQuery = new DbQueryableInfo_Select <TElement>(); outQuery.FromType = type; outQuery.SubQueryInfo = sQuery; outQuery.Join = new List <DbExpression>(); outQuery.OrderBy = new List <DbExpression>(); outQuery.Include = include; outQuery.HaveListNavigation = true; outQuery.Select = new DbExpression(DbExpressionType.Select, select); if (sQuery.GroupBy != null) { // 查看外层是否需要重新构造选择器。如果有分组并且有聚合函数,则需要重新构造选择器。否则外层解析不了聚合函数 // demo=> line 640 bool newSelector = bindings.Any(x => ((MemberAssignment)x).Expression.NodeType == ExpressionType.Call) || newExpression.Arguments.Any(x => x.NodeType == ExpressionType.Call); if (newSelector) { // 1对多导航嵌套查询外层的的第一个表别名固定t0,参数名可随意 ParameterExpression p = Expression.Parameter(newExpression.Type, "__g"); bindings = bindings.ToList(x => (MemberBinding)Expression.Bind(x.Member, Expression.MakeMemberAccess(p, x.Member))); List <Expression> arguments = null; if (newExpression.Members != null) { arguments = new List <Expression>(newExpression.Arguments.Count); for (int i = 0; i < newExpression.Arguments.Count; i++) { var member = newExpression.Members[i]; var arg = Expression.MakeMemberAccess(p, member); arguments.Add(arg); } } newExpression = Expression.New(newExpression.Constructor, arguments, newExpression.Members); initExpression = Expression.MemberInit(newExpression, bindings); lambdaExpression = Expression.Lambda(initExpression, lambdaExpression.Parameters); outQuery.Select = new DbExpression(DbExpressionType.Select, lambdaExpression); } } sQuery = outQuery; } else if (sQuery.Union.Count > 0 && (sQuery.Take > 0 || sQuery.Skip > 0)) { var outQuery = new DbQueryableInfo_Select <TElement>(); outQuery.FromType = type; outQuery.Select = new DbExpression(DbExpressionType.Select, select); outQuery.SubQueryInfo = sQuery; outQuery.Skip = sQuery.Skip; outQuery.Take = sQuery.Take; outQuery.Join = new List <DbExpression>(); outQuery.OrderBy = new List <DbExpression>(); outQuery.OrderBy.AddRange(sQuery.OrderBy); sQuery.OrderBy = new List <DbExpression>(); sQuery.Skip = 0; sQuery.Take = 0; sQuery = outQuery; } return(sQuery); }
// {new App() {Id = p.Id}} private Expression VisitMemberInitImpl(MemberInitExpression node, bool topBinding) { // 如果有一对多的导航属性会产生嵌套的SQL,这时需要强制主表选择的列里面必须包含导航外键 // TODO #对 Bindings 进行排序,保证导航属性的赋值一定要最后面# // 未实现,在书写表达式时人工保证 ## if (node.NewExpression != null) { this.VisitNewImpl(node.NewExpression); } if (_navChainHopper.Count == 0) { _navChainHopper.Add(node.Type.Name); } for (int i = 0; i < node.Bindings.Count; i++) { MemberAssignment binding = node.Bindings[i] as MemberAssignment; if (binding == null) { throw new XFrameworkException("Only 'MemberAssignment' binding supported."); } Type propertyType = (node.Bindings[i].Member as System.Reflection.PropertyInfo).PropertyType; bool isNavigation = !TypeUtils.IsPrimitiveType(propertyType); #region 一般属性 // 非导航属性 if (!isNavigation) { if (binding.Expression.CanEvaluate()) { _builder.Append(binding.Expression.Evaluate().Value, binding.Member, node.Type); } else { base.VisitMemberBinding(binding); } // 选择字段 string newName = AddColumn(_columns, binding.Member.Name); // 添加字段别名 _builder.AppendAs(newName); _builder.Append(','); _builder.AppendNewLine(); } #endregion #region 导航属性 else { // 非显式指定的导航属性需要有 ForeignKeyAttribute if (binding.Expression.NodeType == ExpressionType.MemberAccess && binding.Expression.Acceptable()) { TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(binding.Member.DeclaringType); var attribute = typeRuntime.GetInvokerAttribute <ForeignKeyAttribute>(binding.Member.Name); if (attribute == null) { throw new XFrameworkException("Complex property {{{0}}} must mark 'ForeignKeyAttribute' ", binding.Member.Name); } } // 生成导航属性描述集合,以类名.属性名做为键值 int n = _navChainHopper.Count; string keyName = _navChainHopper.Count > 0 ? _navChainHopper[_navChainHopper.Count - 1] : string.Empty; keyName = !string.IsNullOrEmpty(keyName) ? keyName + "." + binding.Member.Name : binding.Member.Name; Navigation descriptor = new Navigation(keyName, binding.Member); if (!_navigations.ContainsKey(keyName)) { // fix issue# XC 列占一个位 descriptor.Start = _columns.Count; descriptor.FieldCount = GetFieldCount(binding.Expression) + (binding.Expression.NodeType == ExpressionType.MemberAccess && binding.Expression.Acceptable() ? 1 : 0); _navigations.Add(keyName, descriptor); _navChainHopper.Add(keyName); } // 1.不显式指定导航属性,例:a.Client.ClientList // 2.表达式里显式指定导航属性,例:b if (binding.Expression.NodeType == ExpressionType.MemberAccess) { this.VisitNavigation(binding.Expression as MemberExpression, binding.Expression.Acceptable()); } else if (binding.Expression.NodeType == ExpressionType.New) { this.VisitNewImpl(binding.Expression as NewExpression); } else if (binding.Expression.NodeType == ExpressionType.MemberInit) { this.VisitMemberInitImpl(binding.Expression as MemberInitExpression, false); } // 恢复访问链 // 在访问导航属性时可能是 Client.CloudServer,这时要恢复为 Client,以保证能访问 Client 的下一个导航属性 if (_navChainHopper.Count != n) { _navChainHopper.RemoveAt(_navChainHopper.Count - 1); } } #endregion base._visitedMember.Clear(); } return(node); }