//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));
        }
Beispiel #2
0
        // 判定 MemberInit 绑定是否声明了一对多关系的导航
        static bool CheckListNavigation <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 checkListNavgation             = CheckListNavigation <T>(initExpression);
                    if (checkListNavgation)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        // 遍历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);
                    _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 newName = AddColumn(_columns, node.Members != null ? node.Members[i].Name : (argument as MemberExpression).Member.Name);
                        _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._visitedMember.Clear();
            }

            return(node);
        }
Beispiel #4
0
        ///// <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));
            }
        }
Beispiel #5
0
        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);
        }
        // {new App() {Id = p.Id}}
        private Expression VisitMemberInitImpl(MemberInitExpression node, bool topBinding)
        {
            // 如果有一对多的导航属性会产生嵌套的SQL,这时需要强制主表选择的列里面必须包含导航外键
            // TODO #对 Bindings 进行排序,保证导航属性的赋值一定要最后面#
            // 未实现,在书写表达式时人工保证 ##

            if (node.NewExpression != null)
            {
                this.VisitNewImpl(node.NewExpression);
            }
            if (_navChainHopper.Count == 0)
            {
                _navChainHopper.Add(node.Type.Name);
            }

            for (int i = 0; i < node.Bindings.Count; i++)
            {
                MemberAssignment binding = node.Bindings[i] as MemberAssignment;
                if (binding == null)
                {
                    throw new XFrameworkException("Only 'MemberAssignment' binding supported.");
                }

                Type propertyType = (node.Bindings[i].Member as System.Reflection.PropertyInfo).PropertyType;
                bool isNavigation = !TypeUtils.IsPrimitiveType(propertyType);

                #region 一般属性

                // 非导航属性
                if (!isNavigation)
                {
                    if (binding.Expression.CanEvaluate())
                    {
                        _builder.Append(binding.Expression.Evaluate().Value, binding.Member, node.Type);
                    }
                    else
                    {
                        base.VisitMemberBinding(binding);
                    }

                    // 选择字段
                    string newName = AddColumn(_columns, binding.Member.Name);
                    // 添加字段别名
                    _builder.AppendAs(newName);
                    _builder.Append(',');
                    _builder.AppendNewLine();
                }

                #endregion

                #region 导航属性

                else
                {
                    // 非显式指定的导航属性需要有 ForeignKeyAttribute
                    if (binding.Expression.NodeType == ExpressionType.MemberAccess && binding.Expression.Acceptable())
                    {
                        TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(binding.Member.DeclaringType);
                        var             attribute   = typeRuntime.GetInvokerAttribute <ForeignKeyAttribute>(binding.Member.Name);
                        if (attribute == null)
                        {
                            throw new XFrameworkException("Complex property {{{0}}} must mark 'ForeignKeyAttribute' ", binding.Member.Name);
                        }
                    }

                    // 生成导航属性描述集合,以类名.属性名做为键值
                    int    n       = _navChainHopper.Count;
                    string keyName = _navChainHopper.Count > 0 ? _navChainHopper[_navChainHopper.Count - 1] : string.Empty;
                    keyName = !string.IsNullOrEmpty(keyName) ? keyName + "." + binding.Member.Name : binding.Member.Name;
                    Navigation descriptor = new Navigation(keyName, binding.Member);
                    if (!_navigations.ContainsKey(keyName))
                    {
                        // fix issue# XC 列占一个位
                        descriptor.Start      = _columns.Count;
                        descriptor.FieldCount = GetFieldCount(binding.Expression) + (binding.Expression.NodeType == ExpressionType.MemberAccess && binding.Expression.Acceptable() ? 1 : 0);
                        _navigations.Add(keyName, descriptor);
                        _navChainHopper.Add(keyName);
                    }

                    // 1.不显式指定导航属性,例:a.Client.ClientList
                    // 2.表达式里显式指定导航属性,例:b
                    if (binding.Expression.NodeType == ExpressionType.MemberAccess)
                    {
                        this.VisitNavigation(binding.Expression as MemberExpression, binding.Expression.Acceptable());
                    }
                    else if (binding.Expression.NodeType == ExpressionType.New)
                    {
                        this.VisitNewImpl(binding.Expression as NewExpression);
                    }
                    else if (binding.Expression.NodeType == ExpressionType.MemberInit)
                    {
                        this.VisitMemberInitImpl(binding.Expression as MemberInitExpression, false);
                    }

                    // 恢复访问链
                    // 在访问导航属性时可能是 Client.CloudServer,这时要恢复为 Client,以保证能访问 Client 的下一个导航属性
                    if (_navChainHopper.Count != n)
                    {
                        _navChainHopper.RemoveAt(_navChainHopper.Count - 1);
                    }
                }

                #endregion

                base._visitedMember.Clear();
            }

            return(node);
        }
Beispiel #7
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 基元类型

            string name = _reader.GetName(0);
            if (TypeUtils.IsPrimitiveType(typeof(T)) || name == Constant.AUTOINCREMENTNAME)
            {
                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 (typeof(T) == typeof(ExpandoObject) || typeof(T) == typeof(object))
            {
                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);
            TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>();

            if (_definition == null || _definition.Navigations == null || _definition.Navigations.Count == 0)
            {
                // 没有字段映射说明或者没有导航属性
                if (_modelDeserializer == null)
                {
                    _modelDeserializer = InternalTypeDeserializer.GetTypeDeserializer(typeof(T), _reader, _definition != null ? _definition.Columns : null, 0);
                }
                model = (T)_modelDeserializer(_reader);
            }
            else
            {
                // 第一层
                if (_modelDeserializer == null)
                {
                    _modelDeserializer = InternalTypeDeserializer.GetTypeDeserializer(typeof(T), _reader, _definition.Columns, 0, _definition.Navigations.MinIndex);
                }
                model = (T)_modelDeserializer(_reader);
                // 若有 1:n 的导航属性,判断当前行数据与上一行数据是否相同
                if (prevModel != null && _definition.HaveListNavigation)
                {
                    isThisLine = true;
                    foreach (var key in typeRuntime.KeyInvokers)
                    {
                        var invoker = key.Value;
                        var value1  = invoker.Invoke(prevModel);
                        var value2  = invoker.Invoke(model);
                        isThisLine = isThisLine && value1.Equals(value2);
                        if (!isThisLine)
                        {
                            // fix issue#换行时清空上一行的导航键缓存
                            _listNavigationKeys.Clear();
                            break;
                        }
                    }
                }

                // 递归导航属性
                this.Deserialize_Navigation(isThisLine ? prevModel : null, model, string.Empty, isThisLine);
            }

            return(model);

            #endregion
        }
Beispiel #8
0
        // 构造由一对多关系产生的嵌套查询
        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);
        }