protected override Expression VisitUnary(UnaryExpression node) { #if (DEBUGPRINT) System.Diagnostics.Debug.Print("VisitUnary: {0}", node); #endif var expression = base.VisitUnary(node) as UnaryExpression; DbExpression operandExpression = GetDbExpressionForExpression(expression.Operand); switch (expression.NodeType) { case ExpressionType.Not: MapExpressionToDbExpression(expression, DbExpressionBuilder.Not(operandExpression)); break; case ExpressionType.Convert: MapExpressionToDbExpression(expression, DbExpressionBuilder.CastTo(operandExpression, TypeUsageForPrimitiveType(expression.Type))); break; default: throw new NotImplementedException(string.Format("Unhandled NodeType of {0} in LambdaToDbExpressionVisitor.VisitUnary", expression.NodeType)); } return(expression); }
protected override Expression VisitUnary(UnaryExpression node) { #if (DEBUG_VISITS) System.Diagnostics.Debug.Print("VisitUnary: {0}", node); #endif var expression = base.VisitUnary(node) as UnaryExpression; DbExpression operandExpression = GetDbExpressionForExpression(expression.Operand); switch (expression.NodeType) { case ExpressionType.Not: if (operandExpression is DbPropertyExpression) { // Special case to handle "!boolFlag": operandExpression is the property for "boolFlag". // In order for the sql to generate correct, we need to turn this into "boolFlag = 0" // (or we could translate it literally as "not (@noolFlag = 1)") // Figuring out the defaultValue like this should produce the default (0, false, empty) value for the type // we are working with. So checking for "@var = defaultValue" should produce the correct condition. var defaultValue = DbExpressionBuilder.Constant(operandExpression.ResultType, Activator.CreateInstance(expression.Operand.Type)); MapExpressionToDbExpression(expression, DbExpressionBuilder.Equal(operandExpression, defaultValue)); } else { MapExpressionToDbExpression(expression, DbExpressionBuilder.Not(operandExpression)); } break; case ExpressionType.Convert: MapExpressionToDbExpression(expression, DbExpressionBuilder.CastTo(operandExpression, TypeUsageForPrimitiveType(expression.Type))); break; default: throw new NotImplementedException(string.Format("Unhandled NodeType of {0} in LambdaToDbExpressionVisitor.VisitUnary", expression.NodeType)); } return(expression); }
public override DbExpression Visit(DbScanExpression expression) { var table = (EntityType)expression.Target.ElementType; if (table.Properties.All(p => p.Name != IsDeletedColumnName)) { return(base.Visit(expression)); } DbExpression newConditionExpression = null; var binding = expression.Bind(); if (table.Properties.Any(p => p.Name == IsDeletedColumnName)) { var param = DbExpression.FromBoolean(false); var columnProperty = DbExpressionBuilder.Property(DbExpressionBuilder.Variable(binding.VariableType, binding.VariableName), IsDeletedColumnName); if ((columnProperty.ResultType.EdmType.FullName == "Edm.Boolean") && param.ResultType.EdmType.FullName.StartsWith("Oracle", StringComparison.CurrentCultureIgnoreCase) && (param.ResultType.EdmType.Name == "number")) { newConditionExpression = DbExpressionBuilder.Equal(DbExpressionBuilder.CastTo(columnProperty, param.ResultType), param); } else { newConditionExpression = DbExpressionBuilder.Equal(columnProperty, param); } } return(DbExpressionBuilder.Filter(binding, newConditionExpression)); //return binding.Filter( // binding.VariableType // .Variable(binding.VariableName) // .Property(IsDeletedColumnName) // .Equal(DbExpression.FromBoolean(false))); }
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)); } // 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)))); } 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)); }
//public override DbExpression Visit(DbFilterExpression expression) //{ // // If the query contains it's own filter condition (in a .Where() for example), this will be called // // before Visit(DbScanExpression). And it will contain the Predicate specified in that filter. // // Need to inject our dynamic filters here and then 'and' the Predicate. This is necessary so that // // the expressions are properly ()'d. // // It also allows us to attach our dynamic filter into the same DbExpressionBinding so it will avoid // // creating a new sub-query in MS SQL Server. // var predicate = VisitExpression(expression.Predicate); // Visit the predicate so filters will be applied to any child properties inside it (issue #61) // string entityName = expression.Input.Variable.ResultType.EdmType.Name; // //var containers = _ObjectContext.MetadataWorkspace.GetItems<EntityContainer>(DataSpace.SSpace).First(); // // var filterList = FindFiltersForEntitySet(expression.Input.Variable.ResultType.EdmType.MetadataProperties, containers); // var newFilterExpression = BuildFilterExpressionWithDynamicFilters(entityName, new List<string>() { IsDeletedColumnName }, expression.Input, predicate); // if (newFilterExpression != null) // { // // If not null, a new DbFilterExpression has been created with our dynamic filters. // return newFilterExpression; // } // return base.Visit(expression); //} //public override DbExpression Visit(DbScanExpression expression) //{ // var table = (EntityType)expression.Target.ElementType; // if (table.Properties.All(p => p.Name != IsDeletedColumnName)) // { // return base.Visit(expression); // } // string entityName = expression.Target.Name; // var baseResult = base.Visit(expression); // var binding = DbExpressionBuilder.Bind(baseResult); // var newFilterExpression = BuildFilterExpressionWithDynamicFilters(entityName, new List<string>() { IsDeletedColumnName }, binding, null); // if (newFilterExpression != null) // { // // If not null, a new DbFilterExpression has been created with our dynamic filters. // return newFilterExpression; // } // return baseResult; //} //public override DbExpression Visit(DbJoinExpression expression) //{ // DbExpressionBinding left = this.VisitExpressionBinding(expression.Left); // DbExpressionBinding right = this.VisitExpressionBinding(expression.Right); // var rightProperty = DbExpressionBuilder.Property(right.Variable, IsDeletedColumnName); // var predicateExpression = DbExpressionBuilder.Equal(rightProperty, DbExpression.FromBoolean(false)); // var joinCondition = DbExpressionBuilder.And(expression.JoinCondition, predicateExpression); // DbExpression newExpression = expression; // //only re-create the join if something changed // //if (!ReferenceEquals(expression.Left, left) // // || !ReferenceEquals(expression.Right, right) // // || !ReferenceEquals(expression.JoinCondition, joinCondition)) // //{ // switch (expression.ExpressionKind) // { // case DbExpressionKind.InnerJoin: // newExpression = DbExpressionBuilder.InnerJoin(left, right, joinCondition); // break; // case DbExpressionKind.LeftOuterJoin: // newExpression = DbExpressionBuilder.LeftOuterJoin(left, right, joinCondition); // break; // case DbExpressionKind.FullOuterJoin: // newExpression = DbExpressionBuilder.FullOuterJoin(left, right, joinCondition); // break; // } // //} // return newExpression; //} private DbFilterExpression BuildFilterExpressionWithDynamicFilters(string entityName, IEnumerable <string> 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)) { continue; // Already processed this filter - attribute was probably inherited in a base class } processedFilterNames.Add(filter); DbExpression dbExpression; if (!string.IsNullOrEmpty(filter)) { // 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))).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, DataSpace.SSpace)); var param = DbExpression.FromBoolean(false); // 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. 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); } 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)); }