1

I've got a query passed to my service serialised into a set of classes. this object defines conditions in a tree like structure to support AND/ORing data to an infinite depth. I'm then using LinqToSQL to convert this class into a SQL query however my conditions (defined using PredicateBuilder) are ignored!

The PredicateBuilder seems like an obvious solution, my recursive functions build off Expression<Func<Error,bool>> instead of IQueryable<Error> to support this, I iterate over the tree recursively and append AND/OR conditions appropriately.

I call the recursive filter as follows, when debugging I can see the recursive function returning filters correctly - my issue is that these conditions are being ignored and don't surface in the output SQL (please see below) can anyone suggest why this might be?

Please let me know if any additional information is needed or if you believe this approach should work.

if ( hasConditions )
{
    results.Where( RecursiveHandleFilterExpression( query.Criteria ) );
}

This is the function that appends the predicates

private Expression<Func<Error, bool>> RecursiveHandleFilterExpression( FilterExpression filterExpression )
{
    // if anding, start with true Ors start with false
    Expression<Func<Error, bool>> predicate;
    if ( filterExpression.FilterOperator == LogicalOperator.And )
    {
        predicate = PredicateBuilder.True<Error>();
    }
    else
    {
        predicate = PredicateBuilder.False<Error>();
    }

    // apply conditions
    foreach ( ConditionExpression condition in filterExpression.Conditions )
    {
        if ( filterExpression.FilterOperator == LogicalOperator.And )
        {
            predicate.And( ApplyCondition( condition ) );
        }
        else
        {
            predicate.Or( ApplyCondition( condition ) );
        }
    }

    // apply child filters
    foreach ( FilterExpression expression in filterExpression.Filters )
    {
        if ( filterExpression.FilterOperator == LogicalOperator.And )
        {
            predicate.And( RecursiveHandleFilterExpression( expression ) );
        }
        else
        {
            predicate.Or( RecursiveHandleFilterExpression( expression ) );
        }
    }

    return predicate;
}

Generated SQL, obtained through DataContext.Log property, missing the 2 queries passed for the LoggedOn column

SELECT [t2].[ErrorId], [t2].[OrganisationId], [t2].[Severity], [t2].[Source], [t2].[ExceptionMessage], [t2].[InnerExceptionMessage], [t2].[Details], [t2].[LoggedOn]
FROM (
    SELECT [t1].[ErrorId], [t1].[OrganisationId], [t1].[Severity], [t1].[Source], [t1].[ExceptionMessage], [t1].[InnerExceptionMessage], [t1].[Details], [t1].[LoggedOn], [t1].[ROW_NUMBER]
    FROM (
        SELECT ROW_NUMBER() OVER (ORDER BY [t0].[ErrorId], [t0].[OrganisationId], [t0].[Severity], [t0].[Source], [t0].[ExceptionMessage], [t0].[InnerExceptionMessage], [t0].[Details], [t0].[LoggedOn]) AS [ROW_NUMBER], [t0].[ErrorId], [t0].[OrganisationId], [t0].[Severity], [t0].[Source], [t0].[ExceptionMessage], [t0].[InnerExceptionMessage], [t0].[Details], [t0].[LoggedOn]
        FROM [dbo].[Errors] AS [t0]
        WHERE [t0].[OrganisationId] = @p0
        ) AS [t1]
    WHERE [t1].[ROW_NUMBER] BETWEEN @p1 + 1 AND @p1 + @p2
    ) AS [t2]
ORDER BY [t2].[ROW_NUMBER]
-- @p0: Input UniqueIdentifier (Size = -1; Prec = 0; Scale = 0) [f311d7f3-3755-e411-940e-00155d0c0c4b]
-- @p1: Input Int (Size = -1; Prec = 0; Scale = 0) [0]
-- @p2: Input Int (Size = -1; Prec = 0; Scale = 0) [51]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.17929
Dead.Rabit
  • 1,965
  • 1
  • 28
  • 46
  • 1
    I think you only forgot to assign it back to result --> `results = results.Where( RecursiveHandleFilterExpression( query.Criteria ));` – Silvermind Oct 28 '14 at 14:01

1 Answers1

3

The And and Or methods don't mutate the expression. (The objects are immutable.) They return a new expression that represents the operation in question. You are ignoring that return value in your code.

Servy
  • 202,030
  • 26
  • 332
  • 449