Example #1
0
        public static DbExpression Convert(DynamicFilterDefinition filter, DbExpressionBinding binding, DbContext dbContext, DataSpace dataSpace)
        {
            var visitor    = new LambdaToDbExpressionVisitor(filter, binding, dbContext, dataSpace);
            var expression = visitor.Visit(filter.Predicate) as LambdaExpression;

            var dbExpression = visitor.GetDbExpressionForExpression(expression.Body);

            if (dbExpression is DbPropertyExpression)
            {
                //  Special case to handle a condition that is just a plain "boolFlag" or a nullable generic condition.
                //  For a nullable type, we only get here when the filter has either not specified a value for the nullable
                //  parameter or it has specified "null" - both evaluate the same as far as the method prototypes can tell
                //  since the method signature is "param = null".  This needs to generate a sql "is null" condition.
                //  Otherwise, no param value was specified so we are assuming that we need to generate a "positive"
                //  condition.  i.e. the filter just said "b.prop" which generally means "b.prop == true".
                //  To generate that condition correctly for all types (may not necessarily be a bool), we create a condition
                //  like "!(b.prop == [defaultValue])"

                if (IsNullableType(expression.Body.Type))
                {
                    dbExpression = DbExpressionBuilder.IsNull(dbExpression);
                }
                else
                {
                    var defaultValue = DbExpressionBuilder.Constant(dbExpression.ResultType, Activator.CreateInstance(expression.Body.Type));
                    dbExpression = DbExpressionBuilder.Not(DbExpressionBuilder.Equal(dbExpression, defaultValue));
                }
            }

            return(dbExpression);
        }
Example #2
0
        public static DbExpression Convert(DynamicFilterDefinition filter, DbExpressionBinding binding, ObjectContext objectContext)
        {
            var visitor    = new LambdaToDbExpressionVisitor(filter, binding, objectContext);
            var expression = visitor.Visit(filter.Predicate) as LambdaExpression;

            return(visitor.GetDbExpressionForExpression(expression.Body));
        }
        public static DbExpression Convert(DynamicFilterDefinition filter, DbExpressionBinding binding, DbContext dbContext, DataSpace dataSpace)
        {
            var visitor    = new LambdaToDbExpressionVisitor(filter, binding, dbContext, dataSpace);
            var expression = visitor.Visit(filter.Predicate) as LambdaExpression;

            var dbExpression = visitor.GetDbExpressionForExpression(expression.Body);

            if (dbExpression is DbPropertyExpression)
            {
                //  Special case to handle a condition that is just a plan "boolFlag" condition.
                //  In order for the sql to generate correct, we need to turn this into "boolFlag = true"
                //  Figuring out the defaultValue like this should produce the default (0, false, empty) value for the type
                //  we are working with.  So checking then generating a condition of "not (@var = defaultValue)" should produce
                //  the correct condition.
                var defaultValue = DbExpressionBuilder.Constant(dbExpression.ResultType, Activator.CreateInstance(expression.Body.Type));
                dbExpression = DbExpressionBuilder.Not(DbExpressionBuilder.Equal(dbExpression, defaultValue));
            }

            return(dbExpression);
        }
        private Expression MapAnyOrAllExpression(MethodCallExpression node)
        {
            if (_DataSpace != DataSpace.CSpace)
            {
                throw new ApplicationException("Filters on child collections are only supported when using CSpace");
            }

            if ((node.Arguments == null) || (node.Arguments.Count > 2))
            {
                throw new ApplicationException("Any function call has more than 2 arguments");
            }

            //  Visit the first argument so that we can get the DbPropertyExpression which is the source of the method call.
            var sourceExpression     = Visit(node.Arguments[0]);
            var collectionExpression = GetDbExpressionForExpression(sourceExpression);

            //  Visit this DbExpression using the QueryVisitor in case it has it's own filters that need to be applied.
            var queryVisitor = new DynamicFilterQueryVisitorCSpace(_DbContext);

            collectionExpression = collectionExpression.Accept(queryVisitor);

            DbExpression dbExpression;

            if (node.Arguments.Count == 2)
            {
                //  The method call has a predicate that needs to be evaluated.  This must be done against the source
                //  argument - not the current binding.
                var binding = collectionExpression.Bind();

                //  Visit the lambda expression against this binding (which will evaluate all of the
                //  conditions in the expression against this binding and for this filter).
                var lambdaExpression = node.Arguments[1] as LambdaExpression;
                var visitor          = new LambdaToDbExpressionVisitor(_Filter, binding, _DbContext, _DataSpace);
                var subExpression    = visitor.Visit(lambdaExpression) as LambdaExpression;
                var subDbExpression  = visitor.GetDbExpressionForExpression(subExpression.Body);

                //  Create an "Any" or "All" DbExpression from the results
                if (node.Method.Name == "All")
                {
                    dbExpression = DbExpressionBuilder.All(binding, subDbExpression);
                }
                else
                {
                    dbExpression = DbExpressionBuilder.Any(binding, subDbExpression);
                }
            }
            else
            {
                //  This should not even be possible - linq/IEnumerable does not have such a method!
                if (node.Method.Name == "All")
                {
                    throw new ApplicationException("All() with no parameters is not supported");
                }

                //  No predicate so just create an Any DbExpression against the collection expression
                dbExpression = DbExpressionBuilder.Any(collectionExpression);
            }

            MapExpressionToDbExpression(node, dbExpression);
            return(node);
        }
Example #5
0
        private DbFilterExpression BuildFilterExpressionWithDynamicFilters(IEnumerable <DynamicFilterDefinition> filterList, DbExpressionBinding binding, DbExpression predicate)
        {
            if (!filterList.Any())
            {
                return(null);
            }

            var edmType = binding.VariableType.EdmType as EntityType;

            if (edmType == null)
            {
                return(null);
            }

            List <DbExpression> conditionList = new List <DbExpression>();

            HashSet <string> processedFilterNames = new HashSet <string>();

            foreach (var filter in filterList)
            {
                if (processedFilterNames.Contains(filter.FilterName))
                {
                    continue;       //  Already processed this filter - attribute was probably inherited in a base class
                }
                processedFilterNames.Add(filter.FilterName);

                DbExpression dbExpression;
                if (!string.IsNullOrEmpty(filter.ColumnName))
                {
                    //  Single column equality filter
                    var edmProp = edmType.Properties.FirstOrDefault(p => p.Name == filter.ColumnName);
                    if (edmProp == null)
                    {
                        continue;       //  ???
                    }
                    //  database column name is now in edmProp.Name.  Use that instead of filter.ColumnName

                    var columnProperty = DbExpressionBuilder.Property(DbExpressionBuilder.Variable(binding.VariableType, binding.VariableName), edmProp.Name);
                    var param          = columnProperty.Property.TypeUsage.Parameter(filter.CreateDynamicFilterName(filter.ColumnName, DataSpace.CSpace));

                    dbExpression = DbExpressionBuilder.Equal(columnProperty, param);

                    //  When using SSpace, need some special handling for an Oracle Boolean property.
                    //  Not necessary when using CSpace since the translation into the Oracle types has not happened yet.
                }
                else if (filter.Predicate != null)
                {
                    //  Lambda expression filter
                    dbExpression = LambdaToDbExpressionVisitor.Convert(filter, binding, _DbContext, DataSpace.CSpace);
                }
                else
                {
                    throw new System.ArgumentException(string.Format("Filter {0} does not contain a ColumnName or a Predicate!", filter.FilterName));
                }

                if (DynamicFilterExtensions.AreFilterDisabledConditionsAllowed(filter.FilterName))
                {
                    //  Create an expression to check to see if the filter has been disabled and include that check with the rest of the filter expression.
                    //  When this parameter is null, the filter is enabled.  It will be set to true (in DynamicFilterExtensions.GetFilterParameterValue) if
                    //  the filter has been disabled.
                    var boolPrimitiveType = LambdaToDbExpressionVisitor.TypeUsageForPrimitiveType(typeof(bool?), _ObjectContext, DataSpace.CSpace);
                    var isDisabledParam   = boolPrimitiveType.Parameter(filter.CreateFilterDisabledParameterName(DataSpace.CSpace));

                    conditionList.Add(DbExpressionBuilder.Or(dbExpression, DbExpressionBuilder.Not(DbExpressionBuilder.IsNull(isDisabledParam))));
                }
                else
                {
                    conditionList.Add(dbExpression);
                }
            }

            int          numConditions = conditionList.Count;
            DbExpression newPredicate;

            switch (numConditions)
            {
            case 0:
                return(null);

            case 1:
                newPredicate = conditionList.First();
                break;

            default:
                //  Have multiple conditions.  Need to append them together using 'and' conditions.
                newPredicate = conditionList.First();

                for (int i = 1; i < numConditions; i++)
                {
                    newPredicate = newPredicate.And(conditionList[i]);
                }
                break;
            }

            //  'and' the existing Predicate if there is one
            if (predicate != null)
            {
                newPredicate = newPredicate.And(predicate);
            }

            return(DbExpressionBuilder.Filter(binding, newPredicate));
        }
        private DbFilterExpression BuildFilterExpressionWithDynamicFilters(string entityName, IEnumerable <DynamicFilterDefinition> filterList, DbExpressionBinding binding, DbExpression predicate)
        {
            if (!filterList.Any())
            {
                return(null);
            }

            var edmType = binding.VariableType.EdmType as EntityType;

            if (edmType == null)
            {
                return(null);
            }

            List <DbExpression> conditionList = new List <DbExpression>();

            HashSet <string> processedFilterNames = new HashSet <string>();

            foreach (var filter in filterList)
            {
                if (processedFilterNames.Contains(filter.FilterName))
                {
                    continue;       //  Already processed this filter - attribute was probably inherited in a base class
                }
                processedFilterNames.Add(filter.FilterName);

                DbExpression dbExpression;
                if (!string.IsNullOrEmpty(filter.ColumnName))
                {
                    //  Single column equality filter
                    //  Need to map through the EdmType properties to find the actual database/cspace name for the entity property.
                    //  It may be different from the entity property!
                    var edmProp = edmType.Properties.Where(p => p.MetadataProperties.Any(m => m.Name == "PreferredName" && m.Value.Equals(filter.ColumnName))).FirstOrDefault();
                    if (edmProp == null)
                    {
                        continue;       //  ???
                    }
                    //  database column name is now in edmProp.Name.  Use that instead of filter.ColumnName

                    var columnProperty = DbExpressionBuilder.Property(DbExpressionBuilder.Variable(binding.VariableType, binding.VariableName), edmProp.Name);
                    var param          = columnProperty.Property.TypeUsage.Parameter(filter.CreateDynamicFilterName(filter.ColumnName));

                    if ((columnProperty.ResultType.EdmType.FullName == "Edm.Boolean") &&
                        param.ResultType.EdmType.FullName.StartsWith("Oracle", StringComparison.CurrentCultureIgnoreCase) && (param.ResultType.EdmType.Name == "number"))       //  Don't trust Oracle's type name to stay the same...
                    {
                        //  Special handling needed for columnProperty boolean.  For some reason, the Oracle EF driver does not correctly
                        //  set the ResultType to a number(1) in columnProperty like it does in columnProperty.Property.TypeUsage.  That
                        //  results in us trying to do a comparison of a Boolean to a number(1) which causes DbExpressionBuilder.Equal
                        //  to throw an exception.  To get this to process correctly, we need to do a cast on the columnProperty to
                        //  "number(1)" so that it matches the param.ResultType.  And that results in the sql sent to Oracle converting
                        //  the column to the type that it already is...
                        dbExpression = DbExpressionBuilder.Equal(DbExpressionBuilder.CastTo(columnProperty, param.ResultType), param);
                    }
                    else
                    {
                        dbExpression = DbExpressionBuilder.Equal(columnProperty, param);
                    }
                }
                else if (filter.Predicate != null)
                {
                    //  Lambda expression filter
                    dbExpression = LambdaToDbExpressionVisitor.Convert(filter, binding, _ObjectContext);
                }
                else
                {
                    throw new System.ArgumentException(string.Format("Filter {0} does not contain a ColumnName or a Predicate!", filter.FilterName));
                }

                if (DynamicFilterExtensions.AreFilterDisabledConditionsAllowed(filter.FilterName))
                {
                    //  Create an expression to check to see if the filter has been disabled and include that check with the rest of the filter expression.
                    //  When this parameter is null, the filter is enabled.  It will be set to true (in DynamicFilterExtensions.GetFilterParameterValue) if
                    //  the filter has been disabled.
                    var boolPrimitiveType = LambdaToDbExpressionVisitor.TypeUsageForPrimitiveType(typeof(bool?), _ObjectContext);
                    var isDisabledParam   = boolPrimitiveType.Parameter(filter.CreateFilterDisabledParameterName());

                    conditionList.Add(DbExpressionBuilder.Or(dbExpression, DbExpressionBuilder.Not(DbExpressionBuilder.IsNull(isDisabledParam))));
                }
                else
                {
                    conditionList.Add(dbExpression);
                }
            }

            int          numConditions = conditionList.Count;
            DbExpression newPredicate;

            switch (numConditions)
            {
            case 0:
                return(null);

            case 1:
                newPredicate = conditionList.First();
                break;

            default:
                //  Have multiple conditions.  Need to append them together using 'and' conditions.
                newPredicate = conditionList.First();

                for (int i = 1; i < numConditions; i++)
                {
                    newPredicate = newPredicate.And(conditionList[i]);
                }
                break;
            }

            //  'and' the existing Predicate if there is one
            if (predicate != null)
            {
                newPredicate = newPredicate.And(predicate);
            }

            return(DbExpressionBuilder.Filter(binding, newPredicate));
        }
        private DbFilterExpression BuildFilterExpressionWithDynamicFilters(string entityName, IEnumerable <DynamicFilterDefinition> filterList, DbExpressionBinding binding, DbExpression predicate)
        {
            if (!filterList.Any())
            {
                return(null);
            }

            var edmType = binding.VariableType.EdmType as EntityType;

            if (edmType == null)
            {
                return(null);
            }

            List <DbExpression> conditionList = new List <DbExpression>();

            HashSet <string> processedFilterNames = new HashSet <string>();

            foreach (var filter in filterList)
            {
                if (processedFilterNames.Contains(filter.FilterName))
                {
                    continue;       //  Already processed this filter - attribute was probably inherited in a base class
                }
                processedFilterNames.Add(filter.FilterName);

                DbExpression dbExpression;
                if (!string.IsNullOrEmpty(filter.ColumnName))
                {
                    //  Single column equality filter
                    //  Need to map through the EdmType properties to find the actual database/cspace name for the entity property.
                    //  It may be different from the entity property!
                    var edmProp = edmType.Properties.Where(p => p.MetadataProperties.Any(m => m.Name == "PreferredName" && m.Value.Equals(filter.ColumnName))).FirstOrDefault();
                    if (edmProp == null)
                    {
                        continue;       //  ???
                    }
                    //  database column name is now in edmProp.Name.  Use that instead of filter.ColumnName

                    var columnProperty = DbExpressionBuilder.Property(DbExpressionBuilder.Variable(binding.VariableType, binding.VariableName), edmProp.Name);
                    var param          = columnProperty.Property.TypeUsage.Parameter(filter.CreateDynamicFilterName(filter.ColumnName));

                    dbExpression = DbExpressionBuilder.Equal(columnProperty, param);
                }
                else if (filter.Predicate != null)
                {
                    //  Lambda expression filter
                    dbExpression = LambdaToDbExpressionVisitor.Convert(filter, binding, _ObjectContext);
                }
                else
                {
                    throw new System.ArgumentException(string.Format("Filter {0} does not contain a ColumnName or a Predicate!", filter.FilterName));
                }

                //  Create an expression to check to see if the filter has been disabled and include that check with the rest of the filter expression.
                //  When this parameter is null, the filter is enabled.  It will be set to true (in DynamicFilterExtensions.GetFilterParameterValue) if
                //  the filter has been disabled.
                var boolPrimitiveType = _ObjectContext.MetadataWorkspace
                                        .GetPrimitiveTypes(DataSpace.CSpace)
                                        .Where(p => p.ClrEquivalentType == typeof(bool))
                                        .Single();
                var isDisabledParam = DbExpressionBuilder.Parameter(TypeUsage.Create(boolPrimitiveType, new List <Facet>()), filter.CreateFilterDisabledParameterName());
                conditionList.Add(DbExpressionBuilder.Or(dbExpression, DbExpressionBuilder.Not(DbExpressionBuilder.IsNull(isDisabledParam))));
            }

            int          numConditions = conditionList.Count;
            DbExpression newPredicate;

            switch (numConditions)
            {
            case 0:
                return(null);

            case 1:
                newPredicate = conditionList.First();
                break;

            default:
                //  Have multiple conditions.  Need to append them together using 'and' conditions.
                newPredicate = conditionList.First();

                for (int i = 1; i < numConditions; i++)
                {
                    newPredicate = newPredicate.And(conditionList[i]);
                }
                break;
            }

            //  'and' the existing Predicate if there is one
            if (predicate != null)
            {
                newPredicate = newPredicate.And(predicate);
            }

            return(DbExpressionBuilder.Filter(binding, newPredicate));
        }