SqlStatementBuilder holds the specific SQL statement data and populates a build method.
    public SqlPreparationContext (ISqlPreparationContext parentContext, SqlStatementBuilder sqlStatementBuilder)
    {
      ArgumentUtility.CheckNotNull ("sqlStatementBuilder", sqlStatementBuilder);

      _parentContext = parentContext;
      _sqlStatementBuilder = sqlStatementBuilder;
      _mapping = new Dictionary<Expression, Expression>();
    }
 public void SetUp ()
 {
   _generator = new UniqueIdentifierGenerator ();
   _stageMock = new DefaultSqlPreparationStage (
       CompoundMethodCallTransformerProvider.CreateDefault(), ResultOperatorHandlerRegistry.CreateDefault(), _generator);
   _handler = new OfTypeResultOperatorHandler ();
   _sqlStatementBuilder = new SqlStatementBuilder (SqlStatementModelObjectMother.CreateSqlStatementWithCook());
   _context = SqlStatementModelObjectMother.CreateSqlPreparationContext ();
 }
    public virtual Expression ResolveSelectExpression (Expression expression, SqlStatementBuilder sqlStatementBuilder, IMappingResolutionContext context)
    {
      ArgumentUtility.CheckNotNull ("expression", expression);
      ArgumentUtility.CheckNotNull ("sqlStatementBuilder", sqlStatementBuilder);
      ArgumentUtility.CheckNotNull ("context", context);

      var resolvedExpression = ResolvingSelectExpressionVisitor.ResolveExpression (expression, _resolver, this, context, _uniqueIdentifierGenerator, sqlStatementBuilder);
      return ApplyContext (resolvedExpression, SqlExpressionContext.ValueRequired, context);
    }
 public void Initialization_NoSequenceData_ThrowsExeption ()
 {
   var sqlStatement = new SqlStatementBuilder ()
   {
     SelectProjection = Expression.Constant (new Cook ()),
     DataInfo = new StreamedScalarValueInfo(typeof(Cook))
   }.GetSqlStatement ();
   
   new ResolvedSubStatementTableInfo ("c", sqlStatement);
 }
 public void SetUp ()
 {
   _generator = new UniqueIdentifierGenerator ();
   _stage = new DefaultSqlPreparationStage (new CompoundMethodCallTransformerProvider (), new ResultOperatorHandlerRegistry (), _generator);
   _handler = new SumResultOperatorHandler ();
   _sqlStatementBuilder = new SqlStatementBuilder (SqlStatementModelObjectMother.CreateSqlStatement ())
   {
     DataInfo = new StreamedSequenceInfo (typeof (int[]), Expression.Constant (5))
   };
   _context = SqlStatementModelObjectMother.CreateSqlPreparationContext ();
 }
 public void SetUp ()
 {
   _stageMock = MockRepository.GenerateMock<ISqlPreparationStage> ();
   _generator = new UniqueIdentifierGenerator ();
   _handler = new CastResultOperatorHandler ();
   _sqlStatementBuilder = new SqlStatementBuilder (SqlStatementModelObjectMother.CreateSqlStatement ())
   {
     DataInfo = new StreamedSequenceInfo (typeof (Cook[]), Expression.Constant (new Cook ()))
   };
   _context = SqlStatementModelObjectMother.CreateSqlPreparationContext ();
 }
    public void Initialization_ItemTypeWithCovariantSubstatement ()
    {
      var sqlStatement = new SqlStatementBuilder (SqlStatementModelObjectMother.CreateSqlStatement_Resolved (typeof (Cook)))
      {
        SelectProjection = new NamedExpression ("test", Expression.Constant (5)),
        DataInfo = new StreamedSequenceInfo (typeof (object[]), Expression.Constant (0))
      }.GetSqlStatement ();
      var tableInfo = new ResolvedSubStatementTableInfo ("c", sqlStatement);

      Assert.That (tableInfo.ItemType, Is.EqualTo (typeof (object)));
    }
 public void SetUp ()
 {
   _handler = new TestableResultOperatorHandler();
   _resultOperator = new TestChoiceResultOperator (false);
   _statementBuilder = new SqlStatementBuilder();
   _statementBuilder.SelectProjection = Expression.Constant ("select");
   _statementBuilder.DataInfo = new StreamedSequenceInfo (typeof (Cook[]), Expression.Constant (new Cook()));
   _generator = new UniqueIdentifierGenerator();
   _stageMock = MockRepository.GenerateMock<ISqlPreparationStage>();
   _context = SqlStatementModelObjectMother.CreateSqlPreparationContext ();
 }
 public void SetUp ()
 {
   _context = SqlStatementModelObjectMother.CreateSqlPreparationContext();
   _source = ExpressionHelper.CreateMainFromClause<Cook>();
   var source = new UnresolvedTableInfo (typeof (int));
   _sqlTable = new SqlTable (source, JoinSemantics.Inner);
   _parentContext = SqlStatementModelObjectMother.CreateSqlPreparationContext ();
   _parentSource = ExpressionHelper.CreateMainFromClause<Cook>();
   _parentSqlTable = new SqlTable (new UnresolvedTableInfo (typeof (int)), JoinSemantics.Inner);
   _sqlStatementBuilder = new SqlStatementBuilder();
   _contextWithParent = new SqlPreparationContext (_parentContext, _sqlStatementBuilder);
 }
    public void BuildSelectPart_NoEntityExpression ()
    {
      var sqlStatement = new SqlStatementBuilder { SelectProjection = new SqlColumnDefinitionExpression (typeof (string), "t", "FirstName", false), DataInfo = new TestStreamedValueInfo (typeof (object)) }.GetSqlStatement ();
      _stageMock.Expect (
          mock => mock.GenerateTextForSelectExpression (_commandBuilder, sqlStatement.SelectProjection))
          .WhenCalled (mi => ((SqlCommandBuilder) mi.Arguments[0]).Append ("[t].[FirstName]"));
      _stageMock.Replay();

      _generator.BuildSelectPart (sqlStatement, _commandBuilder, false);

      Assert.That (_commandBuilder.GetCommandText(), Is.EqualTo ("SELECT [t].[FirstName]"));
      _stageMock.VerifyAllExpectations();
    }
    public static Expression ResolveExpression (
        Expression expression,
        IMappingResolver resolver,
        IMappingResolutionStage stage,
        IMappingResolutionContext context,
        UniqueIdentifierGenerator generator,
        SqlStatementBuilder sqlStatementBuilder)
    {
      ArgumentUtility.CheckNotNull ("expression", expression);
      ArgumentUtility.CheckNotNull ("resolver", resolver);
      ArgumentUtility.CheckNotNull ("stage", stage);
      ArgumentUtility.CheckNotNull ("context", context);
      ArgumentUtility.CheckNotNull ("generator", generator);
      ArgumentUtility.CheckNotNull ("sqlStatementBuilder", sqlStatementBuilder);

      var entityIdentityResolver = new EntityIdentityResolver (stage, resolver, context);
      var comparisonSplitter = new CompoundExpressionComparisonSplitter ();
      var namedExpressionCombiner = new NamedExpressionCombiner (context);
      var groupAggregateSimplifier = new GroupAggregateSimplifier (stage, context);

      var visitor1 = new ResolvingSelectExpressionVisitor (
          resolver,
          stage,
          context,
          generator,
          entityIdentityResolver,
          comparisonSplitter,
          namedExpressionCombiner,
          groupAggregateSimplifier,
          false,
          sqlStatementBuilder);
      var result1 = visitor1.VisitExpression (expression);

      var visitor2 = new ResolvingSelectExpressionVisitor (
          resolver,
          stage,
          context,
          generator,
          entityIdentityResolver,
          comparisonSplitter,
          namedExpressionCombiner,
          groupAggregateSimplifier,
          true,
          sqlStatementBuilder);
      var result2 = visitor2.VisitExpression (result1);

      return result2;
    }
    public void SetUp ()
    {
      _stageMock = MockRepository.GenerateStrictMock<ISqlPreparationStage>();
      _context = SqlStatementModelObjectMother.CreateSqlPreparationContext ();
      _generator = new UniqueIdentifierGenerator();
      _factory = new SqlPreparationSubStatementTableFactory (_stageMock, _context, _generator);

      var builderForStatementWithOrderings = new SqlStatementBuilder (SqlStatementModelObjectMother.CreateSqlStatementWithCook ())
      {
        Orderings = {
            new Ordering (Expression.Constant ("order1"), OrderingDirection.Desc),
            new Ordering (Expression.Constant ("order2"), OrderingDirection.Asc),
        }
      };
      _statementWithOrderings = builderForStatementWithOrderings.GetSqlStatement ();
    }
    public void Initialization_WithDefaultValues ()
    {
      var statementBuilder = new SqlStatementBuilder();

      Assert.That (statementBuilder.DataInfo, Is.Null);
      Assert.That (statementBuilder.TopExpression, Is.Null);
      Assert.That (statementBuilder.IsDistinctQuery, Is.False);
      Assert.That (statementBuilder.SelectProjection, Is.Null);
      Assert.That (statementBuilder.SqlTables, Is.Empty);
      Assert.That (statementBuilder.Orderings, Is.Empty);
      Assert.That (statementBuilder.WhereCondition, Is.Null);
      Assert.That (statementBuilder.RowNumberSelector, Is.Null);
      Assert.That (statementBuilder.CurrentRowNumberOffset, Is.Null);
      Assert.That (statementBuilder.GroupByExpression, Is.Null);

    }
    public SqlStatement VisitSqlStatement (SqlStatement sqlStatement, SqlExpressionContext expressionContext)
    {
      ArgumentUtility.CheckNotNull ("sqlStatement", sqlStatement);

      if (expressionContext == SqlExpressionContext.PredicateRequired)
        throw new InvalidOperationException ("A SqlStatement cannot be used as a predicate.");

      var statementBuilder = new SqlStatementBuilder (sqlStatement);

      var newSelectProjection = _stage.ApplyContext (sqlStatement.SelectProjection, expressionContext, _mappingResolutionContext);
      statementBuilder.SelectProjection = newSelectProjection;
      statementBuilder.RecalculateDataInfo (sqlStatement.SelectProjection);

      var newSqlStatement = statementBuilder.GetSqlStatement();
      return newSqlStatement.Equals (sqlStatement) ? sqlStatement : newSqlStatement;
    }
    protected SqlPreparationQueryModelVisitor (
        ISqlPreparationContext parentContext,
        ISqlPreparationStage stage,
        UniqueIdentifierGenerator generator,
        ResultOperatorHandlerRegistry resultOperatorHandlerRegistry)
    {
      ArgumentUtility.CheckNotNull ("stage", stage);
      ArgumentUtility.CheckNotNull ("generator", generator);
      ArgumentUtility.CheckNotNull ("resultOperatorHandlerRegistry", resultOperatorHandlerRegistry);

      _stage = stage;
      _generator = generator;
      _resultOperatorHandlerRegistry = resultOperatorHandlerRegistry;

      _sqlStatementBuilder = new SqlStatementBuilder();
      _context = new SqlPreparationContext (parentContext, _sqlStatementBuilder);
    }
    private SqlTable CreateSqlCompatibleSubStatementTable (
        SqlStatement originalStatement, 
        Expression newSelectProjection, 
        Func<ITableInfo, SqlTable> tableCreator)
    {
      // create a new statement equal to the original one, but with the tuple as its select projection
      var builder = new SqlStatementBuilder (originalStatement) { SelectProjection = newSelectProjection };
      builder.RecalculateDataInfo (originalStatement.SelectProjection);

      // clear orderings unless required for TopExpression
      if (originalStatement.TopExpression == null)
        builder.Orderings.Clear();
        
      var newSqlStatement = builder.GetSqlStatement();

      // put new statement into a sub-statement table
      var subStatementTableInfo = new ResolvedSubStatementTableInfo (_uniqueIdentifierGenerator.GetUniqueIdentifier ("q"), newSqlStatement);
      return tableCreator (subStatementTableInfo);
    }
        private SqlStatement ConvertValueStatementToSequenceStatement()
        {
            var newDataInfo = new StreamedSequenceInfo(typeof(IEnumerable <>).MakeGenericType(SqlStatement.DataInfo.DataType), SqlStatement.SelectProjection);

            var adjustedStatementBuilder = new SqlStatementBuilder(SqlStatement)
            {
                DataInfo = newDataInfo
            };

            if (SqlStatement.DataInfo is StreamedSingleValueInfo && SqlStatement.SqlTables.Count != 0)
            {
                // A sub-statement might use a different TopExpression than 1 (or none at all) in order to provoke a SQL error when more than one item is
                // returned. When we convert the statement to a sequence statement, however, we must ensure that the exact "only 1 value is returned"
                // semantics is ensured because we can't provoke a SQL error (but instead would return strange result sets).
                adjustedStatementBuilder.TopExpression = new SqlLiteralExpression(1);
            }

            return(adjustedStatementBuilder.GetSqlStatement());
        }
    public void ResolveSelectExpression ()
    {
      var expression = Expression.Constant (true);
      var sqlStatementBuilder = new SqlStatementBuilder();
      var fakeResult = Expression.Constant (0);
     
      _resolverMock
          .Expect (mock => mock.ResolveConstantExpression (expression))
          .Return (fakeResult);
      _resolverMock
          .Expect (mock => mock.ResolveConstantExpression (fakeResult))
          .Return (fakeResult);
      _resolverMock.Replay();

      var result = _stage.ResolveSelectExpression (expression, sqlStatementBuilder, _mappingResolutionContext);

      _resolverMock.VerifyAllExpectations();

      Assert.That (result, Is.TypeOf (typeof (ConstantExpression)));
      Assert.That (((ConstantExpression) result).Value, Is.EqualTo (0));
    }
    public void SetUp ()
    {
      _stageMock = MockRepository.GenerateMock<ISqlPreparationStage> ();
      _generator = new UniqueIdentifierGenerator ();
      _context = SqlStatementModelObjectMother.CreateSqlPreparationContext ();

      _handler = new SkipResultOperatorHandler ();
      
      _sqlTable = new SqlTable (new UnresolvedTableInfo (typeof (Cook)), JoinSemantics.Inner);
      _selectProjection = new SqlTableReferenceExpression (_sqlTable);

      _ordering = new Ordering (Expression.Constant (7), OrderingDirection.Asc);
      _sqlStatementBuilder = new SqlStatementBuilder
      {
        SelectProjection = _selectProjection,
        DataInfo = new StreamedSequenceInfo (typeof (Cook[]), Expression.Constant (new Cook ())),
        SqlTables = { _sqlTable },
      };

      _tupleCtor = _tupleCtor = typeof (KeyValuePair<Cook, int>).GetConstructor (new[] { typeof (Cook), typeof (int) });
    }
    public void VisitSqlStatement_ExpressionsAndStreamedSequenceDataTypeChanged ()
    {
      var builder = new SqlStatementBuilder (SqlStatementModelObjectMother.CreateSqlStatementWithCook());
      builder.DataInfo = new StreamedSequenceInfo (typeof (IQueryable<>).MakeGenericType (builder.SelectProjection.Type), builder.SelectProjection);
      var sqlStatement = builder.GetSqlStatement();

      var fakeResult = Expression.Constant ("test");
      
      _stageMock
          .Expect (mock => mock.ApplyContext (sqlStatement.SelectProjection, SqlExpressionContext.ValueRequired, _mappingResolutionContext))
          .Return (fakeResult);
     _stageMock.Replay();

      var result = SqlContextSelectionAdjuster.ApplyContext (sqlStatement, SqlExpressionContext.ValueRequired, _stageMock, _mappingResolutionContext);

      _stageMock.VerifyAllExpectations();
      Assert.That (result, Is.Not.SameAs (sqlStatement));
      Assert.That (result.SelectProjection, Is.SameAs (fakeResult));
      Assert.That (result.DataInfo, Is.TypeOf (typeof (StreamedSequenceInfo)));
      Assert.That (((StreamedSequenceInfo) result.DataInfo).ResultItemType, Is.EqualTo (typeof (string)));
      Assert.That (result.DataInfo.DataType, Is.EqualTo (typeof (IQueryable<>).MakeGenericType (fakeResult.Type)));
    }
    public void HandleResultOperator ()
    {
      var predicate = Expression.Constant (true);
      var preparedPredicate = Expression.Constant (false);
      var resultOperator = new AllResultOperator(predicate);
      var sqlStatement = _sqlStatementBuilder.GetSqlStatement();

      var fakePreparedSelectProjection = Expression.Constant (false);

      _stageMock
          .Expect (mock => mock.PrepareWhereExpression (
              Arg<Expression>.Matches(e => e.NodeType == ExpressionType.Not && (((UnaryExpression) e).Operand == predicate)), 
              Arg<ISqlPreparationContext>.Matches(c=>c==_context)))
          .Return (preparedPredicate);
      _stageMock
          .Expect (mock => mock.PrepareSelectExpression (Arg<Expression>.Matches (e => e.NodeType == ExpressionType.Not), Arg.Is (_context)))
          .WhenCalled (
              mi =>
              {
                var selectProjection = (Expression) mi.Arguments[0];
                var expectedSubStatement = new SqlStatementBuilder (sqlStatement) { WhereCondition = preparedPredicate }.GetSqlStatement();
                var expectedExistsExpression = new SqlExistsExpression (new SqlSubStatementExpression (expectedSubStatement));
                var expectedExpression = Expression.Not (expectedExistsExpression);

                SqlExpressionTreeComparer.CheckAreEqualTrees (expectedExpression, selectProjection);
              })
          .Return (fakePreparedSelectProjection);
      _stageMock.Replay();

      _handler.HandleResultOperator (resultOperator, _sqlStatementBuilder, _generator, _stageMock, _context);

      _stageMock.VerifyAllExpectations ();

      Assert.That (_sqlStatementBuilder.DataInfo, Is.TypeOf (typeof (StreamedScalarValueInfo)));
      Assert.That (((StreamedScalarValueInfo) _sqlStatementBuilder.DataInfo).DataType, Is.EqualTo (typeof (Boolean)));

      Assert.That (_sqlStatementBuilder.SelectProjection, Is.SameAs (fakePreparedSelectProjection));
    }
    public void Initialization_WithExistingSqlStatement ()
    {
      var isDistinctQuery = BooleanObjectMother.GetRandomBoolean();
      var selectProjection = Expression.Constant ("select");
      var whereCondition = Expression.Constant (true);
      var topExpression = Expression.Constant ("top");
      var sqlTable = new SqlTable (new ResolvedSimpleTableInfo (typeof (Cook), "CookTable", "c"), JoinSemantics.Inner);
      var ordering = new Ordering (Expression.Constant ("order"), OrderingDirection.Desc);
      var rowNumberSelector = Expression.Constant("selector");
      var currentRowNumberOffset = Expression.Constant(1);
      var groupExpression = Expression.Constant ("group");

      var sqlStatement = new SqlStatement (
          new TestStreamedValueInfo (typeof (int)),
          selectProjection,
          new[] { sqlTable },
          whereCondition,
          groupExpression,
          new[] { ordering },
          topExpression,
          isDistinctQuery,
          rowNumberSelector,
          currentRowNumberOffset);

      var testedBuilder = new SqlStatementBuilder (sqlStatement);

      Assert.That (testedBuilder.SelectProjection, Is.SameAs (selectProjection));
      Assert.That (testedBuilder.TopExpression, Is.SameAs (topExpression));
      Assert.That (testedBuilder.SqlTables[0], Is.SameAs (sqlTable));
      Assert.That (testedBuilder.Orderings[0], Is.SameAs (ordering));
      Assert.That (testedBuilder.WhereCondition, Is.EqualTo (whereCondition));
      Assert.That (testedBuilder.IsDistinctQuery, Is.EqualTo (isDistinctQuery));
      Assert.That (testedBuilder.DataInfo, Is.SameAs (sqlStatement.DataInfo));
      Assert.That (testedBuilder.RowNumberSelector, Is.SameAs (sqlStatement.RowNumberSelector));
      Assert.That (testedBuilder.CurrentRowNumberOffset, Is.SameAs (currentRowNumberOffset));
      Assert.That (testedBuilder.GroupByExpression, Is.SameAs (groupExpression));
    }
    private Expression CheckAndSimplifyEntityWithinSubStatement (SqlSubStatementExpression sqlSubStatementExpression)
    {
      var newSelectProjection = ResolvePotentialEntity (sqlSubStatementExpression.SqlStatement.SelectProjection);
      if (newSelectProjection != sqlSubStatementExpression.SqlStatement.SelectProjection)
      {
        var newSubStatement = new SqlStatementBuilder (sqlSubStatementExpression.SqlStatement) { SelectProjection = newSelectProjection };
        newSubStatement.RecalculateDataInfo (sqlSubStatementExpression.SqlStatement.SelectProjection);

        return newSubStatement.GetSqlStatement ().CreateExpression ();
      }

      return sqlSubStatementExpression;
    }
 protected ResolvingSelectExpressionVisitor (
     IMappingResolver resolver,
     IMappingResolutionStage stage,
     IMappingResolutionContext context,
     UniqueIdentifierGenerator generator, 
     IEntityIdentityResolver entityIdentityResolver,
     ICompoundExpressionComparisonSplitter comparisonSplitter,
     INamedExpressionCombiner namedExpressionCombiner,
     IGroupAggregateSimplifier groupAggregateSimplifier,
     bool resolveEntityRefMemberExpressions,
     SqlStatementBuilder sqlStatementBuilder)
     : base (
         resolver,
         stage,
         context,
         generator,
         entityIdentityResolver,
         comparisonSplitter,
         namedExpressionCombiner,
         groupAggregateSimplifier,
         resolveEntityRefMemberExpressions)
 {
   _sqlStatementBuilder = sqlStatementBuilder;
 }
Example #25
0
        public override string ToString()
        {
            var statementBuilder = new SqlStatementBuilder(this);

            return(statementBuilder.ToString());
        }
    private SqlStatement ConvertValueStatementToSequenceStatement ()
    {
      var newDataInfo = new StreamedSequenceInfo (typeof (IEnumerable<>).MakeGenericType (SqlStatement.DataInfo.DataType), SqlStatement.SelectProjection);

      var adjustedStatementBuilder = new SqlStatementBuilder (SqlStatement) { DataInfo = newDataInfo };
      if (SqlStatement.DataInfo is StreamedSingleValueInfo && SqlStatement.SqlTables.Count!=0)
      {
        // A sub-statement might use a different TopExpression than 1 (or none at all) in order to provoke a SQL error when more than one item is 
        // returned. When we convert the statement to a sequence statement, however, we must ensure that the exact "only 1 value is returned" 
        // semantics is ensured because we can't provoke a SQL error (but instead would return strange result sets).
        adjustedStatementBuilder.TopExpression = new SqlLiteralExpression (1);
      }

      return adjustedStatementBuilder.GetSqlStatement();
    }
 public override string ToString ()
 {
   var statementBuilder = new SqlStatementBuilder (this);
   return statementBuilder.ToString();
 }
    public void ConvertToSqlTable_StreamedSingleValueInfoWithReturnsTrueIfEmpty_JoinSemanticIsChanged ()
    {
      var selectProjection = Expression.Constant (new Cook ());
      var sqlStatement =
          new SqlStatementBuilder
          {
            DataInfo = new StreamedSingleValueInfo (typeof (Cook), true),
            SelectProjection = selectProjection,
            TopExpression = new SqlLiteralExpression (2),
            SqlTables = { new SqlTable (new ResolvedSimpleTableInfo (typeof (Cook), "CookTable", "c"), JoinSemantics.Inner) }
          }.GetSqlStatement ();
      var expression = new SqlSubStatementExpression (sqlStatement);

      var result = expression.ConvertToSqlTable ("q0");

      Assert.That (result.JoinSemantics, Is.EqualTo (JoinSemantics.Left));
      Assert.That (result.TableInfo.GetResolvedTableInfo ().TableAlias, Is.EqualTo ("q0"));
      Assert.That (result.TableInfo, Is.TypeOf (typeof (ResolvedSubStatementTableInfo)));

      var newSubStatement = ((ResolvedSubStatementTableInfo) result.TableInfo).SqlStatement;
      var expectedSubStatement = new SqlStatementBuilder (sqlStatement)
      {
        DataInfo = new StreamedSequenceInfo (typeof (IEnumerable<Cook>), sqlStatement.SelectProjection),
        TopExpression = newSubStatement.TopExpression
      }.GetSqlStatement ();

      SqlExpressionTreeComparer.CheckAreEqualTrees (new SqlLiteralExpression (1), newSubStatement.TopExpression);
      Assert.That (newSubStatement, Is.EqualTo (expectedSubStatement));
    }
    protected override Expression VisitMemberExpression (MemberExpression expression)
    {
      ArgumentUtility.CheckNotNull ("expression", expression);

      var newInnerExpression = VisitExpression (expression.Expression);

      var innerExpressionAsSqlCaseExpression = newInnerExpression as SqlCaseExpression;
      if (innerExpressionAsSqlCaseExpression != null)
      {
        var originalCases = innerExpressionAsSqlCaseExpression.Cases;
        var originalElseCase = innerExpressionAsSqlCaseExpression.ElseCase;
        var newCases = originalCases.Select (c => new SqlCaseExpression.CaseWhenPair (c.When, Expression.MakeMemberAccess (c.Then, expression.Member)));
        var newElseCase = originalElseCase != null ? Expression.MakeMemberAccess (originalElseCase, expression.Member) : null;
        // If there is no else case, ensure that the resulting type is nullable
        var caseExpressionType =
            newElseCase == null && expression.Type.IsValueType && Nullable.GetUnderlyingType (expression.Type) == null
                ? typeof (Nullable<>).MakeGenericType (expression.Type)
                : expression.Type;
        var newSqlCaseExpression = new SqlCaseExpression (caseExpressionType, newCases, newElseCase);
        return VisitExpression (newSqlCaseExpression);
      }

      if (newInnerExpression.NodeType == ExpressionType.Coalesce)
      {
        var innerExpressionAsBinaryExpression = (BinaryExpression) newInnerExpression;
        var newConditionalExpression = Expression.Condition (
            new SqlIsNotNullExpression (innerExpressionAsBinaryExpression.Left), 
            Expression.MakeMemberAccess (innerExpressionAsBinaryExpression.Left, expression.Member), 
            Expression.MakeMemberAccess (innerExpressionAsBinaryExpression.Right, expression.Member));
        return VisitExpression (newConditionalExpression);
      }

      var innerExpressionAsSqlSubStatementExpression = newInnerExpression as SqlSubStatementExpression;
      if (innerExpressionAsSqlSubStatementExpression != null)
      {
        var sqlStatementBuilder = new SqlStatementBuilder (innerExpressionAsSqlSubStatementExpression.SqlStatement);
        var namedExpression = (NamedExpression) sqlStatementBuilder.SelectProjection;
        sqlStatementBuilder.SelectProjection = new NamedExpression (
            namedExpression.Name, VisitExpression (Expression.MakeMemberAccess (namedExpression.Expression, expression.Member)));
        sqlStatementBuilder.RecalculateDataInfo (innerExpressionAsSqlSubStatementExpression.SqlStatement.SelectProjection);
        return new SqlSubStatementExpression (sqlStatementBuilder.GetSqlStatement());
      }

      var memberAsPropertyInfo = expression.Member as PropertyInfo;
      if (memberAsPropertyInfo != null)
      {
        var methodInfo = memberAsPropertyInfo.GetGetMethod();
        if (methodInfo != null)
        {
          var methodCallExpression = Expression.Call (expression.Expression, methodInfo);
          var tranformer = _methodCallTransformerProvider.GetTransformer(methodCallExpression);
          if (tranformer != null)
          {
            var tranformedExpression = tranformer.Transform (methodCallExpression);
            return VisitExpression (tranformedExpression);
          }
        }
      }
      return base.VisitMemberExpression (expression);
    }
    public virtual Expression VisitSqlSubStatementExpression (SqlSubStatementExpression expression)
    {
      ArgumentUtility.CheckNotNull ("expression", expression);

      if (expression.SqlStatement.Orderings.Count > 0 && expression.SqlStatement.TopExpression == null)
      {
        var builder = new SqlStatementBuilder (expression.SqlStatement);
        builder.Orderings.Clear();
        return new SqlSubStatementExpression (builder.GetSqlStatement());
      }
      return expression;
    }
    public ITableInfo VisitUnresolvedGroupReferenceTableInfo (UnresolvedGroupReferenceTableInfo tableInfo)
    {
      var groupSourceSubStatementTableInfo = tableInfo.ReferencedGroupSource.GetResolvedTableInfo() as ResolvedSubStatementTableInfo;
      if (groupSourceSubStatementTableInfo == null)
      {
        var message = string.Format (
            "This SQL generator only supports sequences in from expressions if they are members of an entity or if they come from a GroupBy operator. "
            + "Sequence: '{0}'", tableInfo);
        throw new NotSupportedException (message);
      }

      var groupingSelectExpression = groupSourceSubStatementTableInfo.SqlStatement.SelectProjection as SqlGroupingSelectExpression;
      if (groupingSelectExpression == null)
      {
        throw new NotSupportedException (
            "When a sequence retrieved by a subquery is used in a from expression, the subquery must end with a GroupBy operator.");
      }

      var elementSelectingStatementBuilder = new SqlStatementBuilder (groupSourceSubStatementTableInfo.SqlStatement) { GroupByExpression = null };

      var currentKeyExpression = Expression.MakeMemberAccess (
          new SqlTableReferenceExpression (tableInfo.ReferencedGroupSource), 
          groupingSelectExpression.Type.GetProperty ("Key"));

      var groupKeyJoinCondition = _stage.ResolveWhereExpression (
          Expression.OrElse (
              Expression.AndAlso (new SqlIsNullExpression (groupingSelectExpression.KeyExpression), new SqlIsNullExpression (currentKeyExpression)),
              Expression.AndAlso (
                  Expression.AndAlso (
                      new SqlIsNotNullExpression (groupingSelectExpression.KeyExpression), 
                      new SqlIsNotNullExpression (currentKeyExpression)),
                  Expression.Equal (groupingSelectExpression.KeyExpression, currentKeyExpression))), 
          _context);
      elementSelectingStatementBuilder.AddWhereCondition (groupKeyJoinCondition);

      elementSelectingStatementBuilder.SelectProjection = groupingSelectExpression.ElementExpression;
      elementSelectingStatementBuilder.RecalculateDataInfo (groupingSelectExpression);

      return new ResolvedJoinedGroupingTableInfo (
          _generator.GetUniqueIdentifier("q"), 
          elementSelectingStatementBuilder.GetSqlStatement(), 
          groupingSelectExpression,
          groupSourceSubStatementTableInfo.TableAlias);
    }
    public void ConvertToSqlTable ()
    {
      var selectProjection = Expression.Constant (new Cook());
      var sqlStatement =
          new SqlStatementBuilder { DataInfo = new StreamedSingleValueInfo (typeof (Cook), false), SelectProjection = selectProjection }.
              GetSqlStatement();
      var expression = new SqlSubStatementExpression (sqlStatement);

      var result = expression.ConvertToSqlTable ("q0");

      Assert.That (result.JoinSemantics, Is.EqualTo (JoinSemantics.Inner));
      Assert.That (result.TableInfo.GetResolvedTableInfo().TableAlias, Is.EqualTo ("q0"));
      Assert.That (result.TableInfo, Is.TypeOf (typeof (ResolvedSubStatementTableInfo)));
      
      var newSubStatement = ((ResolvedSubStatementTableInfo) result.TableInfo).SqlStatement;
      var expectedSubStatement = new SqlStatementBuilder (sqlStatement)
      {
        DataInfo = new StreamedSequenceInfo (typeof (IEnumerable<Cook>), sqlStatement.SelectProjection)
      }.GetSqlStatement();

      Assert.That (newSubStatement, Is.EqualTo (expectedSubStatement));
    }