// 判定 MemberInit 绑定是否声明了一对多关系的导航 static bool CheckManyNavigation(LambdaExpression node) { bool hasManyNavgation = false; Expression myExpression = node.Body; while (myExpression.Acceptable()) { if (myExpression.NodeType == ExpressionType.MemberAccess) { myExpression = (myExpression as MemberExpression).Expression; } else if (myExpression.NodeType == ExpressionType.Call) { var methodExpression = myExpression as MethodCallExpression; bool isGetItem = methodExpression.IsGetListItem(); if (isGetItem) { myExpression = methodExpression.Object; } } if (TypeUtils.IsCollectionType(myExpression.Type)) { hasManyNavgation = true; break; } } return(hasManyNavgation); }
// 判定 MemberInit 绑定是否声明了一对多关系的导航 static bool CheckManyNavigation(List <DbExpression> include) { bool hasManyNavgation = false; foreach (DbExpression dbExpression in include) { Expression myExpression = dbExpression.Expressions[0]; if (myExpression.NodeType == ExpressionType.Lambda) { myExpression = (myExpression as LambdaExpression).Body; } else if (myExpression.NodeType == ExpressionType.Call) { myExpression = (myExpression as MethodCallExpression).Object; } // Include 如果包含List<>泛型导航,则可以判定整个查询包含一对多的导航 if (TypeUtils.IsCollectionType(myExpression.Type)) { hasManyNavgation = true; break; } } return(hasManyNavgation); }
// 判定 MemberInit 绑定是否声明了一对多关系的导航 static bool IsHasMany(LambdaExpression node) { bool hasMany = false; Expression myExpression = node.Body; while (myExpression.Visitable()) { if (myExpression.NodeType == ExpressionType.MemberAccess) { myExpression = (myExpression as MemberExpression).Expression; } else if (myExpression.NodeType == ExpressionType.Call) { var methodExpression = myExpression as MethodCallExpression; bool isIndex = methodExpression.IsCollectionIndex(); if (isIndex) { myExpression = methodExpression.Object; } } // 如果包含List<>泛型导航,则可以判定整个查询包含一对多的导航 if (TypeUtils.IsCollectionType(myExpression.Type)) { hasMany = true; break; } } return(hasMany); }
// 判定 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); }
/// <summary> /// 反序列化实体集合 /// </summary> public T Deserialize <T>() { if (TypeUtils.IsCollectionType(typeof(T))) { return(this.DeserializeCollection <T>()); } else { return(this.DeserializeSingle <T>()); } }
// 检查当前成员是否是1:N关系的导航属性 static bool IsManyNavigation(MemberInfo member) { if (member == null) { return(false); } // 仅支持属性和字段*** Type type = null; if (member.MemberType == MemberTypes.Property) { type = ((PropertyInfo)member).PropertyType; } else if (member.MemberType == MemberTypes.Field) { type = ((FieldInfo)member).FieldType; } return(type == null ? false : TypeUtils.IsCollectionType(type)); }
// 检查当前成员是否是1:N关系的导航属性 static bool IsHasMany(MemberInfo info) { if (info == null) { return(false); } // 仅支持属性和字段*** Type type = null; if (info.MemberType == MemberTypes.Property) { type = ((PropertyInfo)info).PropertyType; } else if (info.MemberType == MemberTypes.Field) { type = ((FieldInfo)info).FieldType; } return(type == null ? false : TypeUtils.IsCollectionType(type)); }
// 反序列化导航属性 // @prevLine 前一行数据 // @isLine 是否同一行数据<同一父级> void Deserialize_Navigation(object prevModel, object model, string typeName, bool isThisLine) { // CRM_SaleOrder.Client // CRM_SaleOrder.Client.AccountList Type type = model.GetType(); TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); if (string.IsNullOrEmpty(typeName)) { typeName = type.Name; } //foreach (var kvp in _map.Navigations) foreach (var navigation in _map.PickNavDescriptors) { int start = -1; int end = -1; if (navigation.FieldCount > 0) { start = navigation.StartIndex; end = navigation.StartIndex + navigation.FieldCount; } string keyName = typeName + "." + navigation.Name; if (keyName != navigation.KeyId) { continue; } var navAccessor = typeRuntime.GetMember(navigation.Name); if (navAccessor == null) { continue; } Type navType = navAccessor.DataType; Func <IDataRecord, object> deserializer = null; TypeRuntimeInfo navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navType); object navCollection = null; //if (navType.IsGenericType && navTypeRuntime.GenericTypeDefinition == typeof(List<>)) if (TypeUtils.IsCollectionType(navType)) { // 1:n关系,导航属性为 List<T> navCollection = navAccessor.Invoke(model); if (navCollection == null) { // new 一个列表类型,如果导航属性定义为接口,则默认使用List<T>来实例化 TypeRuntimeInfo navTypeRuntime2 = navType.IsInterface ? TypeRuntimeInfoCache.GetRuntimeInfo(typeof(List <>).MakeGenericType(navTypeRuntime.GenericArguments[0])) : navTypeRuntime; navCollection = navTypeRuntime2.Constructor.Invoke(); navAccessor.Invoke(model, navCollection); } } if (!_deserializers.TryGetValue(keyName, out deserializer)) { deserializer = _deserializerImpl.GetTypeDeserializer(navType.IsGenericType ? navTypeRuntime.GenericArguments[0] : navType, _reader, _map.PickColumns, start, end); _deserializers[keyName] = deserializer; } // 如果整个导航链中某一个导航属性为空,则跳出递归 object navModel = deserializer(_reader); if (navModel != null) { if (navCollection == null) { // 非集合型导航属性 navAccessor.Invoke(model, navModel); // // // } else { // 集合型导航属性 if (prevModel != null && isThisLine) { #region 合并列表 // 判断如果属于同一个主表,则合并到上一行的当前明细列表 // 例:CRM_SaleOrder.Client.AccountList string[] keys = keyName.Split('.'); TypeRuntimeInfo curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); Type curType = curTypeRuntime.Type; MemberAccessorBase curAccessor = null; object curModel = prevModel; for (int i = 1; i < keys.Length; i++) { curAccessor = curTypeRuntime.GetMember(keys[i]); curModel = curAccessor.Invoke(curModel); if (curModel == null) { continue; } curType = curModel.GetType(); curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(curType); // <<<<<<<<<<< 一对多对多关系 >>>>>>>>>> if (curType.IsGenericType && i != keys.Length - 1) { curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(curType); //if (curTypeRuntime.GenericTypeDefinition == typeof(List<>)) if (TypeUtils.IsCollectionType(curType)) { var m = curTypeRuntime.GetMember("get_Count"); int count = Convert.ToInt32(m.Invoke(curModel)); // List.Count if (count > 0) { var m2 = curTypeRuntime.GetMember("get_Item"); curModel = m2.Invoke(curModel, count - 1); // List[List.Count-1] curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(curModel.GetType()); } else { // user.Roles.RoleFuncs=>Roles 列表有可能为空 curModel = null; break; } } } } if (curModel != null) { // 如果有两个以上的一对多关系的导航属性,那么在加入列表之前就需要剔除重复的实体 bool isAny = false; if (_map.PickNavDescriptors.Count > 1) { if (_manyNavigationNumber == null) { _manyNavigationNumber = _map.PickNavDescriptors.Count(x => IsManyNavigation(x.Member)); } if (_manyNavigationNumber != null && _manyNavigationNumber.Value > 1) { if (!_manyNavigationKeys.ContainsKey(keyName)) { _manyNavigationKeys[keyName] = new HashSet <string>(); } curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navModel.GetType()); StringBuilder keyBuilder = new StringBuilder(64); foreach (var m in curTypeRuntime.KeyMembers) { var value = m.Invoke(navModel); keyBuilder.AppendFormat("{0}={1};", m.Name, (value ?? string.Empty).ToString()); } string hash = keyBuilder.ToString(); if (_manyNavigationKeys[keyName].Contains(hash)) { isAny = true; } else { _manyNavigationKeys[keyName].Add(hash); } } } if (!isAny) { // 如果列表中不存在,则添加到上一行的相同导航列表中去 var myAddMethod = navTypeRuntime.GetMember("Add"); myAddMethod.Invoke(curModel, navModel); } } #endregion } else { // 此时的 navTypeRuntime 是 List<> 类型的运行时 // 先添加 List 列表 var myAddMethod = navTypeRuntime.GetMember("Add"); myAddMethod.Invoke(navCollection, navModel); var curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navModel.GetType()); StringBuilder keyBuilder = new StringBuilder(64); foreach (var m in curTypeRuntime.KeyMembers) { var value = m.Invoke(navModel); keyBuilder.AppendFormat("{0}={1};", m.Name, (value ?? string.Empty).ToString()); } string hash = keyBuilder.ToString(); if (!_manyNavigationKeys.ContainsKey(keyName)) { _manyNavigationKeys[keyName] = new HashSet <string>(); } if (!_manyNavigationKeys[keyName].Contains(hash)) { _manyNavigationKeys[keyName].Add(hash); } } } //if (navTypeRuntime.GenericTypeDefinition == typeof(List<>)) navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navTypeRuntime.GenericArguments[0]); if (TypeUtils.IsCollectionType(navTypeRuntime.Type)) { navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navTypeRuntime.GenericArguments[0]); } if (navTypeRuntime.NavMembers.Count > 0) { Deserialize_Navigation(prevModel, navModel, keyName, isThisLine); } } } }
// 构造由一对多关系产生的嵌套查询 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); }