public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext) { var queryCommand = interceptionContext.Result as DbQueryCommandTree; if (queryCommand != null) { var context = interceptionContext.DbContexts.FirstOrDefault(); if (context != null) { DbExpressionVisitor <DbExpression> visitor; #if (USE_CSPACE) // Intercepting CSpace instead of SSpace gives us access to all of the navigation properties // so we are able to handle filters on them as well! if (interceptionContext.OriginalResult.DataSpace == DataSpace.CSpace) { visitor = new DynamicFilterQueryVisitorCSpace(context); } else if ((interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace) && DynamicFilterQueryVisitorCSpace.DoesNotSupportElementMethod(context)) { // Some database (currently Oracle & MySQL) do not support the DbExpression.Element() method that // is needed when applying filters to child entities. To work around that, we need to also // visit the query using this SSpace visitor which will apply those filters on all of the DbScan visits. visitor = new DynamicFilterQueryVisitorSSpace(context); } else { return; } #else // Old method of visiting only in SSpace. Does not support navigation properties but left // here in case need to revert or compare results. if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace) { visitor = new DynamicFilterQueryVisitorOld(context); } else { return; } #endif var newQuery = queryCommand.Query.Accept(visitor); // When using CSpace, must set the useDatabaseNullSemantics parameter to false or nullable types will not have // null values translated to sql like this: ([Extent1].[TenantID] = @p__linq__0) OR (([Extent1].[TenantID] IS NULL) AND (@p__linq__0 IS NULL)) // and will instead just generate sql like this: [Extent1].[TenantID] = @p__linq__0 // If the parameter is not specified, it defaults to true... interceptionContext.Result = new DbQueryCommandTree(queryCommand.MetadataWorkspace, queryCommand.DataSpace, newQuery, true, (interceptionContext.OriginalResult.DataSpace != DataSpace.CSpace)); } } // Can also check for other command types such as DbDeleteCommandTree and DbUpdateCommandTree to change // their behaviors as well. See https://github.com/rowanmiller/Demo-TechEd2014/blob/master/FakeEstate.ListingManager/Models/EFHelpers/SoftDeleteInterceptor.cs //} }
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); }