// 判定 MemberInit 绑定是否声明了一对多关系的导航 static bool CheckManyNavigation <T>(MemberInitExpression node) { for (int i = 0; i < node.Bindings.Count; i++) { // primitive 类型 Type type = (node.Bindings[i].Member as System.Reflection.PropertyInfo).PropertyType; if (TypeUtils.IsPrimitiveType(type)) { continue; } // complex 类型 if (TypeUtils.IsCollectionType(type)) { return(true); } MemberAssignment memberAssignment = node.Bindings[i] as MemberAssignment; if (memberAssignment != null && memberAssignment.Expression.NodeType == ExpressionType.MemberInit) { MemberInitExpression initExpression = memberAssignment.Expression as MemberInitExpression; bool hasManyNavgation = CheckManyNavigation <T>(initExpression); if (hasManyNavgation) { return(true); } } } return(false); }
//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) { // 例: a=> a Type type = lambda.Body.Type; string alias = _aliases.GetTableAlias(lambda); this.VisitAllMember(type, alias); return(node); } else if (lambda.Body.CanEvaluate()) { // 例:a=>1 base.Visit(lambda.Body.Evaluate()); // 选择字段 string newName = AddColumn(_columns, "__Constant__"); // 添加字段别名 _builder.AppendAs(newName); return(node); } else if (lambda.Body.NodeType == ExpressionType.MemberAccess) { // 例: t=> t.a // => SELECT a.ClientId Type type = lambda.Body.Type; return(TypeUtils.IsPrimitiveType(type) ? base.VisitLambda(node) : this.VisitAllMember(type, _aliases.GetTableAlias(lambda.Body), node)); } return(base.VisitLambda(node)); }
/// <summary> /// 获取字段或属性成员的 <see cref="ColumnAttribute"/> /// </summary> /// <param name="member">字段或属性成员</param> /// <param name="reflectedType">调用字段或属性成员的实际类型</param> /// <returns></returns> public static ColumnAttribute GetColumnAttribute(MemberInfo member, Type reflectedType) { if (member == null) { return(null); } if (reflectedType == null) { reflectedType = member.ReflectedType ?? member.DeclaringType; } ColumnAttribute column = null; if (!TypeUtils.IsAnonymousType(reflectedType) && !TypeUtils.IsPrimitiveType(reflectedType)) { var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(reflectedType); var m = typeRuntime.GetMember(member.Name); if (m != null) { column = m.Column; } } return(column); }
protected override Expression VisitMember(MemberExpression node) { // 1.<>h__TransparentIdentifier3.b.Client.ClientName // 2.<>h__TransparentIdentifier3.b.Client.ClientName.Length // 3.<>h__TransparentIdentifier3.b.Client.Address.AddressName // 4.<>h__TransparentIdentifier3.b.ClientName // <>h__TransparentIdentifier2.<>h__TransparentIdentifier3.b.ClientName // <>h__TransparentIdentifier2.<>h__TransparentIdentifier3.b.Client.ClientName // <>h__TransparentIdentifier2.<>h__TransparentIdentifier3.b.Client.Address.AddressName // 5.b.ClientName _visitedMark.Add(node); if (node == null) { return(node); } // => a.ActiveDate == DateTime.Now => a.State == (byte)state if (node.CanEvaluate()) { return(this.VisitConstant(node.Evaluate())); } // => a.Nullable.Value bool isNullable = node.Expression.Type.IsGenericType && node.Member.Name == "Value" && node.Expression.Type.GetGenericTypeDefinition() == typeof(Nullable <>); if (isNullable) { return(this.Visit(node.Expression)); } // => a.Name.Length if (TypeUtils.IsPrimitiveType(node.Expression.Type)) { return(_methodVisitor.VisitMemberMember(node)); } // => <>h__3.b.ClientName if (!node.Expression.Acceptable()) { return(_builder.AppendMember(node, _aliases)); } // => a.Accounts[0].Markets[0].MarketId // => b.Client.Address.AddressName Expression objExpression = node.Expression; bool isMethodCall = objExpression != null && objExpression.NodeType == ExpressionType.Call; if (isMethodCall) { MethodCallExpression methodExpression = objExpression as MethodCallExpression; bool isGetItem = methodExpression.IsGetListItem(); if (isGetItem) { objExpression = methodExpression.Object; } } // => b.Client.Address.AddressName this.VisitNavMember(objExpression, node.Member.Name); return(node); }
// 计算数据库字段数量 private static int GetFieldCount(Expression node) { int num = 0; if (node.NodeType == ExpressionType.Lambda) { node = (node as LambdaExpression).Body; } switch (node.NodeType) { case ExpressionType.MemberInit: var initExpression = node as MemberInitExpression; foreach (var exp in initExpression.NewExpression.Arguments) { if (TypeUtils.IsPrimitiveType(exp.Type)) { num += 1; } else { num += _countComplex(exp); } } foreach (MemberAssignment member in initExpression.Bindings) { num += _countPrimitive(((System.Reflection.PropertyInfo)member.Member).PropertyType); } break; case ExpressionType.MemberAccess: var memberExpression = node as MemberExpression; num += _countComplex(memberExpression); break; case ExpressionType.New: var newExpression = node as NewExpression; //foreach (var exp in newExpression.Arguments) num += _countComplex(exp); if (newExpression.Members != null) { foreach (var member in newExpression.Members) { num += _countPrimitive(((System.Reflection.PropertyInfo)member).PropertyType); } } break; } return(num); }
// 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) { // 例: a=> a Type type = lambda.Body.Type; string alias = _aliases.GetTableAlias(lambda); this.VisitAllMember(type, alias); return(node); } else if (lambda.Body.CanEvaluate()) { // 例:a=>1 base.Visit(lambda.Body.Evaluate()); // 选择字段 string newName = _pickColumns.Add(Constant.CONSTANTNAME); // 添加字段别名 _builder.AppendAs(newName); return(node); } else if (lambda.Body.NodeType == ExpressionType.MemberAccess) { // 例: t=> t.a // => SELECT a.ClientId Type type = lambda.Body.Type; if (!TypeUtils.IsPrimitiveType(type)) { return(this.VisitAllMember(type, _aliases.GetTableAlias(lambda.Body), node)); } else { var newNode = this.VisitWithoutRemark(x => base.VisitLambda(node)); string newName = _pickColumns.Add((lambda.Body as MemberExpression).Member.Name); return(newNode); } } else { var newNode = base.VisitLambda(node); if (_pickColumns.Count == 0) { // 选择字段 string newName = _pickColumns.Add(Constant.CONSTANTNAME); // 添加字段别名 _builder.AppendAs(newName); } return(newNode); } }
// 遍历New表达式的参数集 private Expression VisitNewImpl(NewExpression node) { for (int i = 0; i < node.Arguments.Count; i++) { Expression argument = node.Arguments[i]; Type type = argument.Type; if (argument.NodeType == ExpressionType.Parameter) { //例: new Client(a) string alias = _aliases.GetTableAlias(argument); this.VisitAllMember(type, alias); } else if (argument.CanEvaluate()) { //例: DateTime.Now _builder.Append(argument.Evaluate().Value, node.Members[i], node.Type); string newName = AddColumn(_columns, node.Members != null ? node.Members[i].Name : (argument as MemberExpression).Member.Name, null); _builder.AppendAs(newName); _builder.Append(','); _builder.AppendNewLine(); } else if (argument.NodeType == ExpressionType.MemberAccess || argument.NodeType == ExpressionType.Call) { if (TypeUtils.IsPrimitiveType(type)) { // new Client(a.ClientId) this.Visit(argument); string alias = _visitedMark.Current != null?_aliases.GetTableAlias(_visitedMark.Current) : null; string newName = AddColumn(_columns, node.Members != null ? node.Members[i].Name : (argument as MemberExpression).Member.Name, alias); _builder.AppendAs(newName); _builder.Append(','); _builder.AppendNewLine(); } else { this.VisitNavigation(argument as MemberExpression, false); } } else { throw new XFrameworkException("VisitNewImpl: NodeType '{0}' not supported.", argument.NodeType); } base._visitedMark.Clear(); } return(node); }
// 遍历New表达式的参数集 private Expression VisitNewImpl(NewExpression node) { for (int i = 0; i < node.Arguments.Count; i++) { Expression expression = node.Arguments[i]; Type type = expression.Type; int visitedQty = _visitedMark.Count; if (expression.NodeType == ExpressionType.Parameter) { //例: new Client(a) string alias = _aliases.GetTableAlias(expression); this.VisitAllMember(type, alias); } else if (expression.CanEvaluate()) { //例: DateTime.Now _builder.Append(expression.Evaluate().Value, node.Members[i], node.Type); this.AddPickColumn(node.Members != null ? node.Members[i].Name : (expression as MemberExpression).Member.Name); } else if (expression.NodeType == ExpressionType.MemberAccess || expression.NodeType == ExpressionType.Call) { bool isNavigation = !type.IsEnum && !TypeUtils.IsPrimitiveType(type); if (isNavigation) { this.VisitNavigation(expression as MemberExpression, false); } else { // new Client(a.ClientId) this.Visit(expression); this.AddPickColumn(node.Members != null ? node.Members[i].Name : (expression as MemberExpression).Member.Name); } } else { base.Visit(expression); this.AddPickColumn(node.Members != null ? node.Members[i].Name : (expression as MemberExpression).Member.Name); } // 删除本次访问的成员痕迹 if (_visitedMark.Count != visitedQty) { _visitedMark.Remove(_visitedMark.Count - visitedQty); } } return(node); }
//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) { // 例: a=> a Type type = lambda.Body.Type; string alias = _aliases.GetTableAlias(lambda); this.VisitAllMember(type, alias); return(node); } else if (lambda.Body.CanEvaluate()) { // 例:a=>1 base.Visit(lambda.Body.Evaluate()); // 选择字段 string newName = AddColumn(_columns, "__Constant__", null); // 添加字段别名 _builder.AppendAs(newName); return(node); } else if (lambda.Body.NodeType == ExpressionType.MemberAccess) { // 例: t=> t.a // => SELECT a.ClientId Type type = lambda.Body.Type; if (!TypeUtils.IsPrimitiveType(type)) { return(this.VisitAllMember(type, _aliases.GetTableAlias(lambda.Body), node)); } else { var newNode = base.VisitLambda(node); string alias = _visitedMark.Current != null?_aliases.GetTableAlias(_visitedMark.Current) : null; string newName = AddColumn(_columns, (lambda.Body as MemberExpression).Member.Name, alias); //_builder.AppendAs(newName); //_builder.Append(','); //_builder.AppendNewLine(); return(newNode); } } else { return(base.VisitLambda(node)); } }
/// <summary> /// 判断字段或属性成员的数据类型是否为 ORM 支持的基元类型 /// </summary> /// <param name="member">字段或属性成员</param> /// <returns></returns> public static bool IsPrimitive(MemberInfo member) { Type t = null; if (member != null && member.MemberType == MemberTypes.Field) { t = ((FieldInfo)member).FieldType; } else if (member != null && member.MemberType == MemberTypes.Property) { t = ((PropertyInfo)member).PropertyType; } return(t == null ? false : TypeUtils.IsPrimitiveType(t)); }
///// <summary> ///// 获取XML类型的 SQL 片断 ///// </summary> //protected virtual string GetSqlValueByXml(object value, object dbType, int? size = null, int? precision = null, int? scale = null, ParameterDirection? direction = null) //{ // return this.EscapeQuote(((SqlXml)value).Value, false, true); //} /// <summary> /// 获取其它类型的 SQL 片断 /// </summary> protected virtual string GetSqlValueByOther(object value, object dbType, int?size = null, int?precision = null, int?scale = null, ParameterDirection?direction = null) { if (value is byte[]) { throw new NotSupportedException("System.Byte[] does not support serialization into strings."); } if (TypeUtils.IsPrimitiveType(value.GetType())) { return(value.ToString()); } else { return(this.EscapeQuote(value.ToString(), false, false)); } }
// 访问 New 表达式中的参数 private Expression VisitNewArgumentImpl(Type newType, MemberInfo member, Expression argument) { // 先添加当前字段的访问痕迹标记 if (member != null) { _visitedStack.Add(member, newType); } if (argument.NodeType == ExpressionType.Parameter) { //例: new Client(a) string alias = _aliases.GetTableAlias(argument); this.VisitAllMember(argument.Type, alias); } else if (argument.CanEvaluate()) { //例: DateTime.Now _builder.Append(argument.Evaluate().Value, _visitedStack.Current); this.AddPickColumn(member.Name); } else if (argument.NodeType == ExpressionType.MemberAccess || argument.NodeType == ExpressionType.Call) { bool isNavigation = !argument.Type.IsEnum && !TypeUtils.IsPrimitiveType(argument.Type); if (isNavigation) { this.VisitNavigation(argument as MemberExpression, false); } else { // new Client(a.ClientId) this.Visit(argument); this.AddPickColumn(member.Name); } } else { if (member == null) { throw new XFrameworkException("{0} is not support for NewExpression's arguments."); } base.Visit(argument); this.AddPickColumn(member.Name); } return(argument); }
protected override Expression VisitMember(MemberExpression node) { // 1.<>h__TransparentIdentifier3.b.Client.ClientName // 2.<>h__TransparentIdentifier3.b.Client.ClientName.Length // 3.<>h__TransparentIdentifier3.b.Client.Address.AddressName // 4.<>h__TransparentIdentifier3.b.ClientName // <>h__TransparentIdentifier2.<>h__TransparentIdentifier3.b.ClientName // <>h__TransparentIdentifier2.<>h__TransparentIdentifier3.b.Client.ClientName // <>h__TransparentIdentifier2.<>h__TransparentIdentifier3.b.Client.Address.AddressName // 5.b.ClientName _visitedMember.Add(node); if (node == null) { return(node); } // => a.ActiveDate == DateTime.Now => a.State == (byte)state if (node.CanEvaluate()) { return(this.VisitConstant(node.Evaluate())); } // => a.Name.Length if (TypeUtils.IsPrimitiveType(node.Expression.Type)) { return(_methodVisitor.VisitMemberMember(node)); } // => <>h__3.b.ClientName if (!node.Expression.Acceptable()) { return(_builder.AppendMember(node, _aliases)); } // => b.Client.Address.AddressName this.VisitNavMember(node.Expression, node.Member.Name); return(node); }
/// <summary> /// 获取指定成员的 <see cref="ColumnAttribute"/> /// </summary> /// <param name="member">成员</param> /// <param name="objType">成员所在类型</param> /// <returns></returns> public virtual ColumnAttribute GetColumnAttribute(MemberInfo member, Type objType) { Type dataType = TypeUtils.GetDataType(member); if (dataType == null) { return(null); } ColumnAttribute column = null; Type type = objType != null ? objType : (member.ReflectedType != null ? member.ReflectedType : member.DeclaringType); if (type != null && !TypeUtils.IsAnonymousType(type) && !TypeUtils.IsPrimitiveType(type)) { TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); var invoker = typeRuntime.GetInvoker(member.Name); if (invoker != null) { column = invoker.Column; } } return(column); }
// => new App() {Id = p.Id}} protected override Expression VisitMemberInit(MemberInitExpression node) { // 如果有一对多的导航属性会产生嵌套的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 { this.VisitWithoutRemark(x => this.VisitMemberBinding(binding)); } // 选择字段 this.AddPickColumn(binding.Member.Name); } #endregion 一般属性 #region 导航属性 else { // 非显式指定的导航属性需要有 ForeignKeyAttribute if (binding.Expression.NodeType == ExpressionType.MemberAccess && binding.Expression.Acceptable()) { var 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; var nav = new Navigation(keyName, binding.Member); if (!_navigations.Contains(keyName)) { // fix issue# spliton 列占一个位 nav.StartIndex = _pickColumns.Count; nav.FieldCount = GetFieldCount(binding.Expression) + (binding.Expression.NodeType == ExpressionType.MemberAccess && binding.Expression.Acceptable() ? 1 : 0); _navigations.Add(keyName, nav); _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.VisitMemberInit(binding.Expression as MemberInitExpression); } // 恢复访问链 // 在访问导航属性时可能是 Client.CloudServer,这时要恢复为 Client,以保证能访问 Client 的下一个导航属性 if (_navChainHopper.Count != n) { _navChainHopper.RemoveAt(_navChainHopper.Count - 1); } } #endregion 导航属性 } return(node); }
// 构造由一对多关系产生的嵌套查询 static DbQueryableInfo_Select <TElement> TryBuildOutQuery <TElement>(DbQueryableInfo_Select <TElement> sQueryInfo) { // @havePaging 是否有分页信息 if (sQueryInfo == null || sQueryInfo.SelectExpression == null) { return(sQueryInfo); } Expression select = sQueryInfo.SelectExpression.Expressions[0]; List <DbExpression> include = sQueryInfo.Includes; Type type = sQueryInfo.FromType; // 解析导航属性 如果有 1:n 的导航属性,那么查询的结果集的主记录将会有重复记录 // 这时就需要使用嵌套语义,先查主记录,再关联导航记录 Expression expression = select; var lambdaExpression = expression as LambdaExpression; if (lambdaExpression != null) { expression = lambdaExpression.Body; } var initExpression = expression as MemberInitExpression; var newExpression = expression as NewExpression; bool hasManyNavgation = CheckManyNavigation(include); if (!hasManyNavgation) { hasManyNavgation = initExpression != null && CheckManyNavigation <TElement>(initExpression); } #region 嵌套语义 if (hasManyNavgation) { 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); sQueryInfo.SelectExpression = new DbExpression(DbExpressionType.Select, lambdaExpression); } sQueryInfo.ResultByManyNavigation = true; sQueryInfo.Includes = new List <DbExpression>(0); var outQueryInfo = new DbQueryableInfo_Select <TElement>(); outQueryInfo.FromType = type; outQueryInfo.SubQueryInfo = sQueryInfo; outQueryInfo.Joins = new List <DbExpression>(0); outQueryInfo.OrderBys = new List <DbExpression>(0); outQueryInfo.Includes = include; outQueryInfo.HasManyNavigation = true; outQueryInfo.SelectExpression = new DbExpression(DbExpressionType.Select, select); #region 排序 if (sQueryInfo.OrderBys.Count > 0) { // 是否有分页 bool havePaging = (sQueryInfo.Take > 0 || sQueryInfo.Skip > 0); if (!havePaging) { // 如果没有分页,则OrderBy需要放在外层 outQueryInfo.OrderBys = sQueryInfo.OrderBys; sQueryInfo.OrderBys = new List <DbExpression>(0); } else { // 如果有分页,只有主表/用到的1:1从表放在内层,其它放在外层 List <DbExpression> innerOrderBy = null; foreach (var dbExpression in sQueryInfo.OrderBys) { hasManyNavgation = CheckManyNavigation(dbExpression.Expressions[0] as LambdaExpression); if (!hasManyNavgation) { if (innerOrderBy == null) { innerOrderBy = new List <DbExpression>(); } innerOrderBy.Add(dbExpression); } } if (innerOrderBy != null && innerOrderBy.Count > 0) { outQueryInfo.OrderBys = sQueryInfo.OrderBys; sQueryInfo.OrderBys = innerOrderBy; } } } #endregion #region 分组 if (sQueryInfo.GroupByExpression != 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) { ParameterExpression newParameter = null; List <DbExpression> dbExpressions = null; if (outQueryInfo.Includes != null && outQueryInfo.Includes.Count > 0) { dbExpressions = outQueryInfo.Includes; } else if (outQueryInfo.OrderBys != null && outQueryInfo.OrderBys.Count > 0) { dbExpressions = outQueryInfo.OrderBys; } if (dbExpressions != null && dbExpressions.Count > 0) { newParameter = (dbExpressions[0].Expressions[0] as LambdaExpression).Parameters[0]; } // 1对多导航嵌套查询外层的的第一个表别名固定t0,参数名可随意 var parameterExpression = newParameter != null ? newParameter : Expression.Parameter(newExpression.Type, "__g"); bindings = bindings.ToList(x => (MemberBinding)Expression.Bind(x.Member, Expression.MakeMemberAccess(parameterExpression, 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(parameterExpression, member); arguments.Add(arg); } } newExpression = Expression.New(newExpression.Constructor, arguments, newExpression.Members); initExpression = Expression.MemberInit(newExpression, bindings); lambdaExpression = Expression.Lambda(initExpression, parameterExpression); outQueryInfo.SelectExpression = new DbExpression(DbExpressionType.Select, lambdaExpression); } } #endregion sQueryInfo = outQueryInfo; } #endregion return(sQueryInfo); }
// 构造由一对多关系产生的嵌套查询 static IDbQueryableInfo_Select ParseOutQuery(IDbQueryableInfo_Select dbQuery) { // @havePaging 是否有分页信息 if (dbQuery == null || dbQuery.Select == null) { return(dbQuery); } Expression select = dbQuery.Select.Expressions[0]; List <DbExpression> includes = dbQuery.Includes; Type fromType = dbQuery.FromType; // 解析导航属性 如果有 1:n 的导航属性,那么查询的结果集的主记录将会有重复记录 // 这时就需要使用嵌套语义,先查主记录,再关联导航记录 Expression myExpression = select; var lambdaExpression = myExpression as LambdaExpression; if (lambdaExpression != null) { myExpression = lambdaExpression.Body; } var initExpression = myExpression as MemberInitExpression; var newExpression = myExpression as NewExpression; bool hasMany = DbQueryParser.IsHasMany(includes); if (!hasMany) { hasMany = initExpression != null && IsHasMany(initExpression); } #region 嵌套语义 if (hasMany) { 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); dbQuery.Select = new DbExpression(DbExpressionType.Select, lambdaExpression); } dbQuery.IsParsedByMany = true; dbQuery.Includes = new List <DbExpression>(0); var result_Query = new DbQueryableInfo_Select(); result_Query.FromType = fromType; result_Query.Subquery = dbQuery; result_Query.Joins = new List <DbExpression>(0); result_Query.OrderBys = new List <DbExpression>(0); result_Query.Includes = includes; result_Query.HasMany = true; result_Query.Select = new DbExpression(DbExpressionType.Select, select); #region 排序 if (dbQuery.OrderBys.Count > 0) { // 是否有分页 bool havePaging = (dbQuery.Take > 0 || dbQuery.Skip > 0); if (!havePaging) { // 如果没有分页,则OrderBy需要放在外层 result_Query.OrderBys = dbQuery.OrderBys; dbQuery.OrderBys = new List <DbExpression>(0); } else { // 如果有分页,只有主表/用到的1:1从表放在内层,其它放在外层 List <DbExpression> innerOrderBy = null; foreach (var dbExpression in dbQuery.OrderBys) { hasMany = IsHasMany(dbExpression.Expressions[0] as LambdaExpression); if (!hasMany) { if (innerOrderBy == null) { innerOrderBy = new List <DbExpression>(); } innerOrderBy.Add(dbExpression); } } if (innerOrderBy != null && innerOrderBy.Count > 0) { result_Query.OrderBys = dbQuery.OrderBys; dbQuery.OrderBys = innerOrderBy; } } } #endregion #region 分组 if (dbQuery.GroupBy != null) { // 查看外层是否需要重新构造选择器。如果有分组并且有聚合函数,则需要重新构造选择器。否则外层解析不了聚合函数 // demo => line 1280 bool newSelector = bindings.Any(x => ((MemberAssignment)x).Expression.NodeType == ExpressionType.Call) || newExpression.Arguments.Any(x => x.NodeType == ExpressionType.Call); if (newSelector) { ParameterExpression newParameter = null; List <DbExpression> dbExpressions = null; if (result_Query.Includes != null && result_Query.Includes.Count > 0) { dbExpressions = result_Query.Includes; } else if (result_Query.OrderBys != null && result_Query.OrderBys.Count > 0) { dbExpressions = result_Query.OrderBys; } if (dbExpressions != null && dbExpressions.Count > 0) { newParameter = (dbExpressions[0].Expressions[0] as LambdaExpression).Parameters[0]; } // 1对多导航嵌套查询外层的的第一个表别名固定t0,参数名可随意 var parameterExpression = newParameter != null ? newParameter : Expression.Parameter(newExpression.Type, "__g"); bindings = bindings.ToList(x => (MemberBinding)Expression.Bind(x.Member, Expression.MakeMemberAccess(parameterExpression, 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(parameterExpression, member); arguments.Add(arg); } } newExpression = Expression.New(newExpression.Constructor, arguments, newExpression.Members); initExpression = Expression.MemberInit(newExpression, bindings); lambdaExpression = Expression.Lambda(initExpression, parameterExpression); result_Query.Select = new DbExpression(DbExpressionType.Select, lambdaExpression); } } #endregion dbQuery = result_Query; } #endregion return(dbQuery); }
// 构造由一对多关系产生的嵌套查询 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); }
/// <summary> /// 将 <see cref="IDataRecord"/> 上的当前行反序列化为实体 /// </summary> /// <param name="prevModel">前一行数据</param> /// <param name="isThisLine">是否同一行数据</param> internal T Deserialize(object prevModel, out bool isThisLine) { isThisLine = false; #region 基元类型 if (_isPrimitive == null) { _isPrimitive = TypeUtils.IsPrimitiveType(typeof(T)) || _reader.GetName(0) == Constant.AUTO_INCREMENT_NAME; } if (_isPrimitive.Value) { if (_reader.IsDBNull(0)) { return(default(T)); } var obj = _reader.GetValue(0); if (obj.GetType() != typeof(T)) { // fix#Nullable<T> issue if (!typeof(T).IsGenericType) { obj = Convert.ChangeType(obj, typeof(T)); } else { Type g = typeof(T).GetGenericTypeDefinition(); if (g != typeof(Nullable <>)) { throw new NotSupportedException(string.Format("type {0} not suppored.", g.FullName)); } obj = Convert.ChangeType(obj, Nullable.GetUnderlyingType(typeof(T))); } } return((T)obj); } #endregion #region 动态类型 if (_isDynamic) { ExpandoObject obj = new ExpandoObject(); var result = ((IDictionary <string, object>)obj); for (int i = 0; i < _reader.FieldCount; i++) { var value = _reader.GetValue(i); if (value == DBNull.Value) { value = null; } result.Add(_reader.GetName(i), value); } return((dynamic)obj); } #endregion #region 实体类型 T model = default(T); if (_map == null || _map.PickNavDescriptors == null || _map.PickNavDescriptors.Count == 0) { // 没有字段映射说明或者没有导航属性 if (_modelDeserializer == null) { _modelDeserializer = _deserializerImpl.GetTypeDeserializer(typeof(T), _reader, _map != null ? _map.PickColumns : null, 0); } model = (T)_modelDeserializer(_reader); } else { // 第一层 if (_modelDeserializer == null) { _modelDeserializer = _deserializerImpl.GetTypeDeserializer(typeof(T), _reader, _map.PickColumns, 0, _map.PickNavDescriptors.MinIndex); } model = (T)_modelDeserializer(_reader); // 若有 1:n 的导航属性,判断当前行数据与上一行数据是否相同 if (prevModel != null && _map.HasMany) { isThisLine = true; foreach (var m in _typeRuntime.KeyMembers) { var value1 = m.Invoke(prevModel); var value2 = m.Invoke(model); isThisLine = isThisLine && value1.Equals(value2); if (!isThisLine) { // Fix issue#换行时清空上一行的导航键缓存 _manyNavigationKeys.Clear(); break; } } } // 递归导航属性 this.Deserialize_Navigation(isThisLine ? prevModel : null, model, string.Empty, isThisLine); } return(model); #endregion }
// {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 alias = _visitedMark.Current != null?_aliases.GetTableAlias(_visitedMark.Current) : null; string newName = AddColumn(_columns, binding.Member.Name, alias); // 添加字段别名 _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._visitedMark.Clear(); } return(node); }