// 构造由一对多关系产生的嵌套查询
        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>
 /// 获取当前类型的所有成员
 /// </summary>
 protected virtual IEnumerable <MemberInfo> GetTypeMembers(Type type, bool @private)
 {
     return(TypeUtils.GetMembers(type, @private));
 }
Beispiel #3
0
        /// <summary>
        /// 访问字段或者属性表达式
        /// </summary>
        /// <param name="node">字段或者成员表达式</param>
        /// <returns></returns>
        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


            if (node == null)
            {
                return(node);
            }
            // => a.ActiveDate == DateTime.Now  => a.State == (byte)state
            if (node.CanEvaluate())
            {
                return(this.VisitConstant(node.Evaluate()));
            }
            // => DateTime.Now
            if (node.Type == typeof(DateTime) && node.Expression == null)
            {
                return(_methodVisitor.Visit(node, MethodCall.MemberMember));
            }
            // => a.Nullable.Value
            bool isNullable = node.Expression.Type.IsGenericType && node.Member.Name == "Value" && node.Expression.Type.GetGenericTypeDefinition() == typeof(Nullable <>);

            if (isNullable)
            {
                this.Visit(node.Expression);
                return(node);
            }

            // 记录访问成员栈
            _visitedStack.Add(node);

            // => a.Name.Length
            if (TypeUtils.IsPrimitiveType(node.Expression.Type))
            {
                return(_methodVisitor.Visit(node, MethodCall.MemberMember));
            }
            // => <>h__3.b.ClientName
            if (!node.Expression.Visitable())
            {
                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 isIndex = methodExpression.IsCollectionIndex();
                if (isIndex)
                {
                    objExpression = methodExpression.Object;
                }
            }
            // => b.Client.Address.AddressName
            this.VisitNavMember(objExpression, node.Member.Name);

            return(node);
        }
        // => 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);
        }
 /// <summary>
 /// 初始化 <see cref="TypeRuntimeInfo"/> 类的新实例
 /// </summary>
 /// <param name="type">类型声明</param>
 /// <param name="includePrivates">包含私有成员</param>
 internal TypeRuntimeInfo(Type type, bool includePrivates)
 {
     _type            = type;
     _isAnonymousType = TypeUtils.IsAnonymousType(_type);
     _includePrivates = includePrivates;
 }
Beispiel #6
0
        /// <summary>
        /// 生成 value 对应的 SQL 片断
        /// </summary>
        /// <param name="value">SQL值</param>
        /// <param name="token">解析上下文</param>
        /// <param name="m">value 对应的成员</param>
        /// <returns></returns>
        public string GetSqlValue(object value, ResolveToken token, MemberVisitedStack.VisitedMember m)
        {
            ColumnAttribute column = m != null?TypeUtils.GetColumnAttribute(m.Member, m.ReflectedType) : null;

            return(this.GetSqlValue(value, token, column));
        }
Beispiel #7
0
        /// <summary>
        /// 生成 value 对应的 SQL 片断
        /// </summary>
        /// <param name="value">SQL值</param>
        /// <param name="token">解析SQL命令时的参数上下文</param>
        /// <param name="dbType">数据类型</param>
        /// <param name="size">长度</param>
        /// <param name="precision">精度</param>
        /// <param name="scale">小数位</param>
        /// <param name="direction">查询参数类型</param>
        /// <returns></returns>
        public string GetSqlValue(object value, ResolveToken token,
                                  object dbType, int?size = null, int?precision = null, int?scale = null, ParameterDirection?direction = null)
        {
            // https://docs.microsoft.com/zh-cn/sql/t-sql/data-types/datetime2-transact-sql?view=sql-server-2017
            // 1.Date 3个字节,DateTime 8个字节 DateTime2 <=4 6个字节 其它8个字节,外加1个字节存储精度
            // 2.如果转换时没有指定数据类型的长度,则SQServer自动提供长度为30
            // 3.隐式转换优先级 https://docs.microsoft.com/zh-cn/sql/t-sql/data-types/data-type-precedence-transact-sql?view=sql-server-2017
            // 4.参数化查询只需要重写 CreateParameter

            if (value == null)
            {
                return("NULL");
            }
            else if (token != null && token.Parameters != null)
            {
                // 参数化 ##########
                if (!(value is string) && !(value is byte[]) && (value is IEnumerable))
                {
                    return(this.GetSqlValue(value as IEnumerable, token, dbType, size, precision, scale));
                }
                else
                {
                    return(this.AddParameter(value, token, dbType, size, precision, scale, direction).ParameterName);
                }
            }
            else
            {
                // 非参数化 ##########

                Type type = value.GetType();
                // 枚举类型
                if (type.IsEnum)
                {
                    return(this.GetSqlValueByEnum(value));
                }
                // Guid 类型
                else if (value is Guid)
                {
                    return(this.GetSqlValueByGuid(value));
                }
                // 数据类型
                else if (TypeUtils.IsNumberType(type))
                {
                    return(this.GetSqlValueByNumber(value));
                }
                // byte[] 类型
                else if (value is byte[])
                {
                    return(this.GetSqlValueByBytes(value));
                }
                // 布尔类型
                else if (value is bool)
                {
                    return(this.GetSqlValueByBoolean(value, dbType));
                }
                // 字符类型
                else if (value is char || value is string)
                {
                    return(this.GetSqlValueByString(value, dbType, size));
                }
                // 时间类型
                else if (value is TimeSpan)
                {
                    return(this.GetSqlValueByTime(value, dbType, scale));
                }
                // 日期类型
                else if (value is DateTime)
                {
                    return(this.GetSqlValueByDateTime(value, dbType, scale));
                }
                // 日期类型(带时区)
                else if (value is DateTimeOffset)
                {
                    return(this.GetSqlValueByDateTimeOffset(value, dbType, scale));
                }
                // 集合类型
                else if (value is IEnumerable)
                {
                    return(this.GetSqlValue(value as IEnumerable, token, dbType, size, precision, scale));
                }
                else
                {
                    throw new NotSupportedException(string.Format("type {0} not supported serialize to string", type.FullName));
                }
            }
        }
        // 构造由一对多关系产生的嵌套查询
        static DbQueryableInfo_Select <TElement> ParseOutQuery <TElement>(DbQueryableInfo_Select <TElement> dbQuery)
        {
            // @havePaging 是否有分页信息

            if (dbQuery == null || dbQuery.Select == null)
            {
                return(dbQuery);
            }

            Expression          select   = dbQuery.Select.Expressions[0];
            List <DbExpression> includes = dbQuery.Includes;
            Type type = dbQuery.FromEntityType;

            // 解析导航属性 如果有 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 <TElement>(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.SubQueryOfMany = true;
                dbQuery.Includes       = new List <DbExpression>(0);

                var result_Query = new DbQueryableInfo_Select <TElement>();
                result_Query.FromEntityType = type;
                result_Query.SubQueryInfo   = 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);
        }
Beispiel #9
0
        /// <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.AUTOINCREMENTNAME;
            }
            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.Navigations == null || _map.Navigations.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.Navigations.MinIndex);
                }
                model = (T)_modelDeserializer(_reader);
                // 若有 1:n 的导航属性,判断当前行数据与上一行数据是否相同
                if (prevModel != null && _map.HasMany)
                {
                    isThisLine = true;
                    foreach (var invoker in _typeRuntime.KeyInvokers)
                    {
                        var value1 = invoker.Invoke(prevModel);
                        var value2 = invoker.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
        }
Beispiel #10
0
        // 反序列化导航属性
        // @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.Navigations)
            {
                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.KeyName)
                {
                    continue;
                }

                var navInvoker = typeRuntime.GetInvoker(navigation.Name);
                if (navInvoker == null)
                {
                    continue;
                }

                Type navType = navInvoker.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 = navInvoker.Invoke(model);
                    if (navCollection == null)
                    {
                        // new 一个列表类型,如果导航属性定义为接口,则默认使用List<T>来实例化
                        TypeRuntimeInfo navTypeRuntime2 = navType.IsInterface
                            ? TypeRuntimeInfoCache.GetRuntimeInfo(typeof(List <>).MakeGenericType(navTypeRuntime.GenericArguments[0]))
                            : navTypeRuntime;
                        navCollection = navTypeRuntime2.ConstructInvoker.Invoke();
                        navInvoker.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)
                    {
                        // 非集合型导航属性
                        navInvoker.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;
                            MemberInvokerBase curInvoker     = null;
                            object            curModel       = prevModel;

                            for (int i = 1; i < keys.Length; i++)
                            {
                                curInvoker = curTypeRuntime.GetInvoker(keys[i]);
                                curModel   = curInvoker.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 invoker = curTypeRuntime.GetInvoker("get_Count");
                                        int count   = Convert.ToInt32(invoker.Invoke(curModel));    // List.Count
                                        if (count > 0)
                                        {
                                            var invoker2 = curTypeRuntime.GetInvoker("get_Item");
                                            curModel       = invoker2.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.Navigations.Count > 1)
                                {
                                    if (_manyNavigationNumber == null)
                                    {
                                        _manyNavigationNumber = _map.Navigations.Count(x => IsHasMany(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 invoker in curTypeRuntime.KeyInvokers)
                                        {
                                            var value = invoker.Invoke(navModel);
                                            keyBuilder.AppendFormat("{0}={1};", invoker.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.GetInvoker("Add");
                                    myAddMethod.Invoke(curModel, navModel);
                                }
                            }

                            #endregion
                        }
                        else
                        {
                            // 此时的 navTypeRuntime 是 List<> 类型的运行时
                            // 先添加 List 列表
                            var myAddMethod = navTypeRuntime.GetInvoker("Add");
                            myAddMethod.Invoke(navCollection, navModel);

                            var           curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navModel.GetType());
                            StringBuilder keyBuilder     = new StringBuilder(64);

                            foreach (var invoker in curTypeRuntime.KeyInvokers)
                            {
                                var value = invoker.Invoke(navModel);
                                keyBuilder.AppendFormat("{0}={1};", invoker.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.NavInvokers.Count > 0)
                    {
                        Deserialize_Navigation(prevModel, navModel, keyName, isThisLine);
                    }
                }
            }
        }