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