コード例 #1
0
        protected override Expression VisitMember(MemberExpression m)
        {
            var expression = Visit(m.Expression);

            if (expression is ConstantExpression constExpr)
            {
                var container = constExpr.Value;
                var member    = m.Member;

                object value          = null;
                var    valueRetrieved = false;
                switch (member)
                {
                case FieldInfo field:
                    value          = field.GetValue(container);
                    valueRetrieved = true;
                    break;

                case PropertyInfo prop:
                    value          = prop.GetValue(container, null);
                    valueRetrieved = true;
                    break;
                }

                if (valueRetrieved)
                {
                    var dbObject = _dbFactory.BuildConstant(value, true);
                    _state.ResultStack.Push(dbObject);
                    return(m);
                }
            }

            var typeInfo = m.Type.GetTypeInfo();

            if (m.Expression.Type.IsAnonymouse())
            {
                var dbRef = (DbReference)_state.ResultStack.Peek();
                if (dbRef.RefSelection.ContainsKey(m.Member.Name))
                {
                    var dbObj = dbRef.RefSelection[m.Member.Name];

                    // pop out the dbRef from the stack, it was the result of
                    // translate a parameter, and it is not required for following translation
                    _state.ResultStack.Pop();
                    _state.ResultStack.Push(dbObj);

                    return(m);
                }
            }

            if (m.Expression.Type.IsGrouping())
            {
                var dbRef = (DbReference)_state.ResultStack.Pop();

                var dbSelect = dbRef.OwnerSelect;
                if (dbSelect.GroupBys.IsSingleKey)
                {
                    var kColumn = dbSelect.GroupBys.Single();
                    _state.ResultStack.Push(kColumn);
                }
                else
                {
                    _state.ResultStack.Push(dbRef);
                }

                return(m);
            }

            // if the member is a queryable entity, we need to translate it
            // into a relation, which means a join
            var entityInfo = _infoProvider.FindEntityInfo(m.Type);

            if (entityInfo != null)
            {
                var dbObj   = _state.ResultStack.Pop();
                var refCol  = dbObj as IDbRefColumn;
                var fromRef = refCol != null ? refCol.Ref : (DbReference)dbObj;

                var fromEntity = _infoProvider.FindEntityInfo(m.Expression.Type);
                var relation   = fromEntity.GetRelation(m.Member.Name);

                var dbJoin = GetOrCreateJoin(relation, fromRef, refCol ?? fromRef.ReferredRefColumn);

                // RefColumnAlias is used as alias in case we need to create a ref column for this dbRef
                dbJoin.To.RefColumnAlias = m.Member.Name;

                if (refCol != null)
                {
                    refCol = _dbFactory.BuildRefColumn(dbJoin.To, m.Member.Name);

                    if (dbJoin.To.Referee is IDbSelect subSelect)
                    {
                        refCol.RefTo = subSelect.Selection.OfType <IDbRefColumn>().Single();
                    }

                    _state.ResultStack.Push(refCol);
                    return(m);
                }

                _state.ResultStack.Push(relation.IsChildRelation ? dbJoin.To.Referee : dbJoin.To);
                return(m);
            }

            if (typeInfo.Namespace.StartsWith("System"))
            {
                var dbObj  = _state.ResultStack.Pop();
                var refCol = dbObj as IDbRefColumn;
                var dbRef  = refCol != null ? refCol.Ref : (DbReference)dbObj;

                var fieldInfo = _infoProvider.FindFieldInfo(m.Member);
                var col       = _dbFactory.BuildColumn(dbRef, fieldInfo.DbName, fieldInfo.ValType);
                _state.ResultStack.Push(col);

                // if we create a column whose DbRef is using by a RefColumn
                // we need to make sure the column is added to the ref column's owner select
                // This normally happen when we are accessing a column from a child relation
                refCol = refCol ?? dbRef.ReferredRefColumn;

                // if the ref column is not now, and it is referring another ref column
                // we need to make sure the column we translated is in the sub select which
                // owns the ref column that referred by the current refColumn
                refCol?.RefTo?.AddToReferedSelect(_dbFactory, fieldInfo.DbName, fieldInfo.ValType);

                return(m);
            }

            return(base.VisitMember(m));
        }