/// <summary> /// 添加导航属性关联 /// </summary> protected override void ResoveNavMember() { if (this.NavMembers == null || this.NavMembers.Count == 0) { return; } // 如果有一对多的导航属性,肯定会产生嵌套查询。那么内层查询别名肯定是t0,所以需要清掉 if (this.HasMany) { _aliases = new TableAlias(_aliases.HoldQty); } //开始产生 USING 子句 ISqlBuilder jf = this.JoinFragment; int index = -1; // 未生成USING子句 if (_aliases.HoldQty <= 1) { jf.AppendNewLine(); jf.Append(_keywordName); } else { jf.Append(','); jf.AppendNewLine(); } foreach (var nav in this.NavMembers) { index++; string key = nav.KeyId; MemberExpression m = nav.Expression; TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(m.Expression.Type); ForeignKeyAttribute attribute = typeRuntime.GetMemberAttribute <ForeignKeyAttribute>(m.Member.Name); string innerKey = string.Empty; string outerKey = key; string innerAlias = string.Empty; if (!m.Expression.Visitable()) { innerKey = m.Expression.NodeType == ExpressionType.Parameter ? (m.Expression as ParameterExpression).Name : (m.Expression as MemberExpression).Member.Name; } else { MemberExpression mLeft = null; if (m.Expression.NodeType == ExpressionType.MemberAccess) { mLeft = m.Expression as MemberExpression; } else if (m.Expression.NodeType == ExpressionType.Call) { mLeft = (m.Expression as MethodCallExpression).Object as MemberExpression; } string name = TypeRuntimeInfoCache.GetRuntimeInfo(mLeft.Type).TableName; innerAlias = _aliases.GetJoinTableAlias(name); if (string.IsNullOrEmpty(innerAlias)) { string keyLeft = mLeft.GetKeyWidthoutAnonymous(); if (this.NavMembers.Contains(keyLeft)) { innerKey = keyLeft; } innerAlias = _aliases.GetNavTableAlias(innerKey); } } string alias1 = !string.IsNullOrEmpty(innerAlias) ? innerAlias : _aliases.GetTableAlias(innerKey); string alias2 = _aliases.GetNavTableAlias(outerKey); // 补充与USING字符串同等间距的空白 if (_aliases.HoldQty > 1 || index > 0) { jf.Append(_pad); } Type type = m.Type; var typeRumtime2 = TypeRuntimeInfoCache.GetRuntimeInfo(type); if (type.IsGenericType) { type = type.GetGenericArguments()[0]; } jf.AppendMember(typeRumtime2.TableName, typeRumtime2.IsTemporary); jf.Append(' '); jf.Append(alias2); if (_onPhrase.Length > 0) { _onPhrase.Append(" AND "); } for (int i = 0; i < attribute.InnerKeys.Length; i++) { if (attribute.InnerKeys[i].StartsWith(Constant.CONSTANT_FOREIGNKEY, StringComparison.Ordinal)) { _onPhrase.Append(attribute.InnerKeys[i].Substring(7)); } else { _onPhrase.Append(alias1); _onPhrase.Append('.'); _onPhrase.AppendMember(attribute.InnerKeys[i]); } _onPhrase.Append(" = "); if (attribute.OuterKeys[i].StartsWith(Constant.CONSTANT_FOREIGNKEY, StringComparison.Ordinal)) { _onPhrase.Append(attribute.OuterKeys[i].Substring(7)); } else { _onPhrase.Append(alias2); _onPhrase.Append('.'); _onPhrase.AppendMember(attribute.OuterKeys[i]); } } if (nav.Predicate != null) { string alias = _aliases.GetNavTableAlias(nav.KeyId); var visitor = new NavPredicateExpressionVisitor(_provider, _aliases, nav.Predicate, alias); visitor.Write(_onPhrase); } if (index < this.NavMembers.Count - 1) { jf.Append(','); jf.AppendNewLine(); } } }
// 添加导航属性关联 protected override void ResoveNavMember() { if (base.NavMembers == null || base.NavMembers.Count == 0) { return; } // 如果有一对多的导航属性,肯定会产生嵌套查询。那么内层查询别名肯定是t0,所以需要清掉 if (this.HasMany) { _aliases = new TableAlias(_aliases.HoldQty); } //开始产生LEFT JOIN 子句 ISqlBuilder builder = this.JoinFragment; foreach (var nav in base.NavMembers) { string key = nav.KeyId; MemberExpression m = nav.Expression; TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(m.Expression.Type); ForeignKeyAttribute attribute = typeRuntime.GetMemberAttribute <ForeignKeyAttribute>(m.Member.Name); string innerKey = string.Empty; string outerKey = key; string innerAlias = string.Empty; if (!m.Expression.Visitable()) { innerKey = m.Expression.NodeType == ExpressionType.Parameter ? (m.Expression as ParameterExpression).Name : (m.Expression as MemberExpression).Member.Name; } else { MemberExpression mLeft = null; if (m.Expression.NodeType == ExpressionType.MemberAccess) { mLeft = m.Expression as MemberExpression; } else if (m.Expression.NodeType == ExpressionType.Call) { mLeft = (m.Expression as MethodCallExpression).Object as MemberExpression; } string name = TypeRuntimeInfoCache.GetRuntimeInfo(mLeft.Type).TableName; innerAlias = _aliases.GetJoinTableAlias(name); if (string.IsNullOrEmpty(innerAlias)) { string keyLeft = mLeft.GetKeyWidthoutAnonymous(); if (base.NavMembers.Contains(keyLeft)) { innerKey = keyLeft; } innerAlias = _aliases.GetNavTableAlias(innerKey); } } string alias1 = !string.IsNullOrEmpty(innerAlias) ? innerAlias : _aliases.GetTableAlias(innerKey); string alias2 = _aliases.GetNavTableAlias(outerKey); builder.AppendNewLine(); builder.Append("LEFT JOIN "); Type type = m.Type; if (type.IsGenericType) { type = type.GetGenericArguments()[0]; } var typeRuntime2 = TypeRuntimeInfoCache.GetRuntimeInfo(type); builder.AppendMember(typeRuntime2.TableName, !typeRuntime2.IsTemporary); builder.Append(" "); builder.Append(alias2); bool withNoLock = !typeRuntime2.IsTemporary && _context.NoLock && !string.IsNullOrEmpty(_provider.WidthNoLock); if (withNoLock) { builder.Append(' '); builder.Append(_provider.WidthNoLock); } builder.Append(" ON "); for (int i = 0; i < attribute.InnerKeys.Length; i++) { if (attribute.InnerKeys[i].StartsWith(Constant.CONSTANT_FOREIGNKEY, StringComparison.Ordinal)) { builder.Append(attribute.InnerKeys[i].Substring(7)); } else { builder.Append(alias1); builder.Append('.'); builder.AppendMember(attribute.InnerKeys[i]); } builder.Append(" = "); if (attribute.OuterKeys[i].StartsWith(Constant.CONSTANT_FOREIGNKEY, StringComparison.Ordinal)) { builder.Append(attribute.OuterKeys[i].Substring(7)); } else { builder.Append(alias2); builder.Append('.'); builder.AppendMember(attribute.OuterKeys[i]); } if (i < attribute.InnerKeys.Length - 1) { builder.Append(" AND "); } } if (nav.Predicate != null) { string alias = _aliases.GetNavTableAlias(nav.KeyId); var visitor = new NavPredicateExpressionVisitor(_provider, _aliases, nav.Predicate, alias); visitor.Write(builder); } } }
/// <summary> /// 访问导航属性 /// </summary> /// <param name="expression">导航属性表达式</param> /// <param name="memberName">成员名称</param> /// <returns></returns> protected virtual string VisitNavMember(Expression expression, string memberName = null) { // 表达式 => b.Client.Address.AddressName Expression node = expression; Stack <NavMember> stack = null; string alias = string.Empty; while (node != null && node.Visitable()) { if (node.NodeType != ExpressionType.MemberAccess) { break; } if (stack == null) { stack = new Stack <NavMember>(); } var member = node as MemberExpression; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(member.Expression.Type); ForeignKeyAttribute attribute = typeRuntime.GetMemberAttribute <ForeignKeyAttribute>(member.Member.Name); if (attribute == null) { break; } string key = member.GetKeyWidthoutAnonymous(); stack.Push(new NavMember(key, member)); node = member.Expression; if (node.NodeType == ExpressionType.Call) { node = (node as MethodCallExpression).Object; } } if (stack != null && stack.Count > 0) { while (stack != null && stack.Count > 0) { NavMember nav = stack.Pop(); Type type = nav.Expression.Type; if (type.IsGenericType) { type = type.GetGenericArguments()[0]; } var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); // 检查表达式是否由 GetTable<,>(path) 显式指定过别名 alias = _aliases.GetGetTableAlias(nav.KeyId); if (string.IsNullOrEmpty(alias)) { // 如果没有,检查查询表达式是否显示指定该表关联 alias = _aliases.GetJoinTableAlias(typeRuntime.TableName); } if (string.IsNullOrEmpty(alias)) { // 如果没有,则使用导航属性别名 alias = _aliases.GetNavTableAlias(nav.KeyId); if (!_navMembers.Contains(nav.KeyId)) { _navMembers.Add(nav); } } // 例: a.Client.ClientId if (stack.Count == 0 && !string.IsNullOrEmpty(memberName)) { _builder.AppendMember(alias, memberName); } } } else { // => SelectMany 也会产生类似 'b.Client.Address.AddressName' 这样的表达式 alias = _aliases.GetTableAlias(expression); _builder.AppendMember(alias, memberName); } // Fix issue# Join 表达式显式指定导航属性时时,alias 为空 return(alias); }
// => Client = a.Client.CloudServer private Expression VisitNavigation(MemberExpression node, bool visitNavigation, Expression pickExpression = null, Expression predicate = null) { string alias = string.Empty; Type type = node.Type; if (node.Visitable()) { // 例: Client = a.Client.CloudServer // Fix issue# Join 表达式显式指定导航属性时时,alias 为空 // Fix issue# 多个导航属性时 AppendNullColumn 只解析当前表达式的 int index = 0; int num = this.NavMembers != null ? this.NavMembers.Count : 0; alias = this.VisitNavMember(node); if (num != this.NavMembers.Count) { foreach (var nav in this.NavMembers) { index += 1; if (index < this.NavMembers.Count && index > num) { alias = _aliases.GetNavTableAlias(nav.KeyId); } else { alias = _aliases.GetNavTableAlias(nav.KeyId); type = nav.Expression.Type; if (index == this.NavMembers.Count) { nav.Predicate = predicate; } } } } else { } } else { // 例: Client = b alias = _aliases.GetTableAlias(node); type = node.Type; } if (type.IsGenericType) { type = type.GetGenericArguments()[0]; } if (pickExpression == null) { this.VisitAllMember(type, alias); } else { // Include 中选中的字段 Expression expression = pickExpression; if (expression.NodeType == ExpressionType.Lambda) { expression = (pickExpression as LambdaExpression).Body; } if (expression.NodeType == ExpressionType.New) { var newExpression = expression as NewExpression; for (int i = 0; i < newExpression.Arguments.Count; i++) { var memberExpression = newExpression.Arguments[i] as MemberExpression; if (memberExpression == null) { throw new XFrameworkException("MemberExpression required at the {0} arguments.", i); } if (memberExpression.CanEvaluate()) { base.Visit(memberExpression); } else { _builder.AppendMember(alias, memberExpression.Member.Name); } this.AddPickColumn(newExpression.Members != null ? newExpression.Members[i].Name : memberExpression.Member.Name); } } else if (expression.NodeType == ExpressionType.MemberInit) { var initExpression = expression as MemberInitExpression; for (int i = 0; i < initExpression.Bindings.Count; i++) { var binding = initExpression.Bindings[i] as MemberAssignment; if (binding == null) { throw new XFrameworkException("Only 'MemberAssignment' binding supported."); } var memberExpression = binding.Expression as MemberExpression; if (memberExpression == null) { throw new XFrameworkException("MemberExpression required at the {0} arguments.", i); } if (memberExpression.CanEvaluate()) { base.Visit(memberExpression); } else { _builder.AppendMember(alias, memberExpression.Member.Name); } this.AddPickColumn(binding.Member.Name); } } else { throw new NotSupportedException(string.Format("Include method not support {0}", expression.NodeType)); } } if (visitNavigation) { AddSplitOnColumn(node.Member, alias); } return(node); }