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)); }